一、使用 pthread_create 函数创建线程
pthread_create 是Linux下常见的创建线程的方法,它包含在 pthread 库中。通过它我们可以在一个程序中创建多个线程来并行处理任务。
下面是一个简单的示例,通过 pthread_create 创建两个线程:
#include <iostream> #include <pthread.h> using namespace std; void* threadFunc(void* arg) { int num = *((int*) arg); cout << "Thread #" << num << ": hello world!" << endl; return NULL; } int main(int argc, char** argv) { pthread_t thread1, thread2; int thread1Num = 1, thread2Num = 2; pthread_create(&thread1, NULL, threadFunc, &thread1Num); pthread_create(&thread2, NULL, threadFunc, &thread2Num); pthread_join(thread1, NULL); pthread_join(thread2, NULL); cout << "Main thread exiting" << endl; return 0; }
在上面的代码中,我们通过调用 pthread_create 函数来创建两个线程 thread1 和 thread2。每个线程都调用 threadFunc 函数,在这个函数里我们输出了一个简单的 "hello world"。最后,我们通过调用 pthread_join 函数来等待两个线程的结束,然后程序才能正常退出。
二、使用 std::thread 类创建线程
C++11 标准引入了 std::thread 类,可以方便地创建线程。相比于 pthread_create 函数,std::thread 更具有面向对象的特征,更加易于使用。
下面是一个使用 std::thread 创建线程的示例:
#include <iostream> #include <thread> using namespace std; void threadFunc(int num) { cout << "Thread #" << num << ": hello world!" << endl; } int main(int argc, char** argv) { thread thread1(threadFunc, 1); thread thread2(threadFunc, 2); thread1.join(); thread2.join(); cout << "Main thread exiting" << endl; return 0; }
在上面的代码中,我们通过使用 std::thread 类创建了两个线程 thread1 和 thread2。和 pthread_create 不同的是,我们使用了类的构造函数来创建线程,也就是说,每个线程都是一个对象。在构造线程的时候,我们将要执行的函数和它的参数作为参数传入线程构造函数。和 pthread_create 一样,我们也需要调用 join() 函数等待线程结束。
三、线程同步与互斥
在多线程程序中,通常都需要处理线程同步和互斥的问题。如果多个线程同时访问同一个数据,可能会导致数据出错或者延时。因此,我们需要使用锁来控制对共享资源的访问,避免多个线程同时访问同一个数据。
下面是一个使用 pthreads 库来保护临界段的示例:
#include <iostream> #include <pthread.h> using namespace std; int count = 0; pthread_mutex_t count_mutex; void* threadFunc(void* arg) { for (int i = 0; i < 5; i++) { pthread_mutex_lock(&count_mutex); count++; cout << "Thread #" << *((int*) arg) << " count = " << count << endl; pthread_mutex_unlock(&count_mutex); } return NULL; } int main(int argc, char** argv) { pthread_t thread1, thread2; int thread1Num = 1, thread2Num = 2; pthread_mutex_init(&count_mutex, NULL); pthread_create(&thread1, NULL, threadFunc, &thread1Num); pthread_create(&thread2, NULL, threadFunc, &thread2Num); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_mutex_destroy(&count_mutex); cout << "Main thread exiting" << endl; return 0; }
在上面的示例中,我们使用了 pthreads 库的互斥量来保护全局变量 count。在 threadFunc 函数中,我们使用 pthread_mutex_lock 和 pthread_mutex_unlock 函数来加锁和解锁。这样,当两个线程同时访问 count 变量时,一次只能有一个线程进行访问,避免了数据错乱。
除了使用互斥量外,C++11 中也提供了 std::mutex 来进行锁操作。std::mutex 的用法和 pthread_mutex_t 是类似的,使用起来更加方便。
四、线程池
线程池是一种常见的多线程编程技术,通常用于处理大量并发请求。线程池中创建好多个线程,等待队列中的任务。当任务来临时,线程池中的线程会从队列中取出任务进行处理,完成后再次回到队列中等待新的任务。
下面是一个简单的线程池实现:
#include <iostream> #include <thread> #include <queue> #include <mutex> #include <condition_variable> using namespace std; class ThreadPool { public: ThreadPool(int numThreads) { for (int i = 0; i < numThreads; i++) { threads.emplace_back([this] { for (;;) { function<void()> task; { unique_lock<mutex> lock(this->queueMutex); this->condition.wait(lock, [this] { return !this->tasks.empty() || this->stop; }); if (this->stop && this->tasks.empty()) { return; } task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } }); } } ~ThreadPool() { { unique_lock<mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (auto &thread : threads) { thread.join(); } } template <class Func, class... Args> auto enqueue(Func&& func, Args&&... args) -> future<typename result_of<Func(Args...)>::type> { using return_type = typename result_of<Func(Args...)>::type; auto task = make_shared<packaged_task<return_type()>>( bind(forward<Func>(func), forward<Args>(args)...) ); future<return_type> res = task->get_future(); { unique_lock<mutex> lock(queueMutex); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } private: vector<thread> threads; queue<function<void()>> tasks; mutex queueMutex; condition_variable condition; bool stop = false; }; void threadFunc(int num) { cout << "Thread #" << num << " hello world!" << endl; } int main(int argc, char** argv) { ThreadPool pool(4); pool.enqueue(threadFunc, 1); pool.enqueue(threadFunc, 2); pool.enqueue(threadFunc, 3); pool.enqueue(threadFunc, 4); return 0; }
在上面的示例中,我们实现了一个简单的线程池。它包含了一个线程池的类 ThreadPool。它使用 std::vector 存储所有线程,std::queue 存储所有任务,std::mutex和 std::condition_variable 用于线程同步。
线程池的构造函数需要输入线程数量 numThreads 作为参数,它会在构造函数中创建 numThreads 个线程。enqueue 函数可以添加新任务到队列中,添加的任务将会在队列中等待线程池中的线程去执行。
在 main 函数中,我们创建了一个线程池 pool,并且通过 pool.enqueue 函数添加了 4 个任务,并由线程池执行。