一、使用 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 个任务,并由线程池执行。
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/240097.html
微信扫一扫
支付宝扫一扫