您的位置:

我是线程[1]操作详解

一、线程的定义

线程是计算机中最小的可执行单元,是操作系统中进行CPU调度和分配的基本单位,一个进程可以包含多个线程。不同于进程间的资源隔离,不同线程之间可以共享进程的资源,如内存、文件描述符等。线程主要包括线程标识符、程序计数器、寄存器集合、栈和线程本地存储区域等组成部分。

二、线程的创建和销毁

在C++11标准中,线程的创建和销毁主要由std::thread类来实现,创建线程的基本形式如下:

#include <thread>
void function_to_execute();
std::thread t(function_to_execute); //创建一个新线程

创建新线程时需要指定线程需要执行的函数名或lambda表达式,在这里function_to_execute()为线程函数,std::thread t是线程对象。销毁线程主要有detach()函数和join()函数,前者将线程与线程对象解绑,允许线程对象独立运行,后者等待线程执行完成后才继续执行主线程。

三、线程的同步

多个线程之间进行资源共享时,需要注意同步问题。引入同步机制可以防止多个线程同时对同一个资源进行访问并产生冲突,通常采用互斥量和条件变量实现同步。在C++11标准中,互斥量(std::mutex)用于保护共享数据资源,条件变量(std::condition_variable)提供了一种等待通知的机制。

#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void function1() {
    std::unique_lock<std::mutex> lck(mtx);
    // 同步执行
    cv.wait(lck, []{return ready;});
    // 继续执行
}

void function2() {
    // 准备数据
    {
        std::lock_guard<std::mutex> lck(mtx);
        // 获得锁
        ready = true;
    }
    cv.notify_one();
    // 通知另一个线程
}

上面代码中,mutex被用来保护一个boolean类型的ready变量。function1()和function2()都需要使用控制ready变量的线程同步机制来确保ready已经被设置。function1()上锁,调用wait()函数开始等待,直到另一个线程上锁并调用notify_one()函数来解除等待并继续执行。function2()设置ready后,调用notify_one()函数向另一个线程通知数据已准备好。

四、线程的安全性问题

在多线程编程中,可能出现数据竞争、死锁、饥饿、优先级反转等问题。其中数据竞争是典型的线程不安全问题,通常通过使用原子类型、锁等手段来解决。原子类型是一种特殊类型,可以保证对其操作的“原子性”,即线程安全。std::atomic类提供了常用的原子类型,如std::atomic_int、std::atomic_bool等。

#include <atomic>
std::atomic_int a(0);
void increase() { a++; }

上面代码中,std::atomic_int类的对象a可以通过该类提供的++操作进行原子递增,从而保证多个线程之间的线程安全。

五、线程的优化

优化多线程程序的性能是程序员们需要面对的挑战之一。线程池是一个常用的优化多线程程序的手段。线程池的本质是维护一定数量的线程,用于执行需要并发处理的任务,线程池可以避免反复创建和销毁线程的开销,降低了线程创建带来的性能影响。

#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <queue>

std::queue<std::function<void()>> taskQueue;
std::mutex taskMutex;
std::condition_variable taskCV;
std::atomic_bool stop_flag(false);

void worker() {
    std::function<void()> task;
    while (true) {
        {
            std::unique_lock<std::mutex> lock(taskMutex);
            taskCV.wait(lock, []{ return !taskQueue.empty() || stop_flag.load(); });
            if (stop_flag && taskQueue.empty()) {
                return;
            } else if (!taskQueue.empty()) {
                task = taskQueue.front();
                taskQueue.pop();
            } else {
                continue;
            }
        }
        task();
    }
}

class ThreadPool {
public:
    ThreadPool(size_t numThreads) {
        for (size_t i = 0; i < numThreads; i++) {
            workers.emplace_back(worker);
        }
    }

    ~ThreadPool() {
        stop_flag = true;
        taskCV.notify_all();
        for (auto& worker : workers) {
            worker.join();
        }
    }

    template <typename F, typename ...Args>
    auto addTask(F&& f, Args&& ...args) {
        auto task = std::make_shared<std::function<void()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::unique_lock<std::mutex> lock(taskMutex);
        taskQueue.emplace([task](){ (*task)(); });
        taskCV.notify_one();
        return task;
    }

private:
    std::vector<std::thread> workers;
};

ThreadPool pool(4);

void thread_func(int x, int y) {
    for (int i = x; i < y; i++) {
        printf("thread id: %d\n", std::this_thread::get_id());
        printf("i = %d\n", i);
    }
}

void test_thread_pool() {
    for (int i = 0; i < 10; i++) {
        auto task = pool.addTask(thread_func, i * 10, i * 10 + 10);
    }
}

上述代码实现了一个简单的线程池,包括添加任务、等待任务、执行任务等基本功能。代码通过std::thread和std::mutex等C++标准库提供的线程相关的类和函数实现。