九、多线程
6. 条件变量
在多线程编程中,一个或多个线程可能需要等待某个条件的发生,然后才能继续执行,而不是一直忙等。这种等待通常会占用CPU资源。条件变量提供了一种机制,使得线程可以等待某个条件的发生,同时释放CPU资源给其他线程使用。当一个线程需要等待某个条件时,它会先获取互斥锁,然后调用条件变量的等待函数,此时互斥锁会被释放,线程 进入等待队列 。当条件发生时,另一个线程会获取互斥锁,然后调用条件变量的 通知 函数,通知等待的线程条件已经满足。总而言之,条件变量就是一种 等待队列 + 通知唤醒 的机制。
这里条件变量的使用方法和互斥锁几乎一样,这里不再描述。
我们来简单使用一下条件变量:
Makefile:
testCond:testCond.cc
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
rm -f testCond
testCond.cc:
#include <iostream>
#include <string>
#include <pthread.h>
#include <vector>
#include <unistd.h>
using namespace std;
// 全局的条件变量
pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;
// 全局的互斥锁
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
void* MasterCore(void* args)
{
sleep(3);
cout << "Master 线程开始工作了" << endl;
string name = (const char*)args;
while (true)
{
// 唤醒等待队列头部的线程
pthread_cond_signal(&gcond);
cout << "Masther 线程唤醒了一个线程" << endl;
// 唤醒所有线程
//pthread_cond_broadcast(&gcond);
//cout << "Master 线程广播了一个信号, 唤醒了所有线程" << endl;
sleep(1);
}
}
void* SlaverCore(void* args)
{
string name = (const char*)args;
while (true)
{
// 加锁
pthread_mutex_lock(&gmutex);
// 等待条件变量
pthread_cond_wait(&gcond, &gmutex);
// 解锁
pthread_mutex_unlock(&gmutex);
cout << "当前被叫醒的线程是: " << name << endl;
}
}
void StartMaster(vector<pthread_t>* tidsptr)
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, MasterCore, (void*)"Master Thread");
if (n == 0)
{
cout << "Master Thread Created" << endl;
}
tidsptr->emplace_back(tid);
}
void StartSlaver(vector<pthread_t>* tidsptr, int threadnum = 3)
{
for (int i = 0; i < threadnum; i++)
{
char* name = new char[64];
snprintf(name, 64, "Slaver-%d", i + 1);
pthread_t tid;
int n = pthread_create(&tid, nullptr, SlaverCore, name);
if (n == 0)
{
cout << "Slaver Thread " << name << " Created" << endl;
tidsptr->emplace_back(tid);
}
}
}
void WaitThread(vector<pthread_t>& tids)
{
for (auto& tid : tids)
{
pthread_join(tid, nullptr);
}
}
int main()
{
vector<pthread_t> tids;
StartMaster(&tids);
StartSlaver(&tids, 5);
WaitThread(tids);
return 0;
}
7. 生产者消费者模型
生产者消费者模型是一种常见的并发编程模型,用于解决多个线程之间的协作问题。在生产者消费者模型中,有三种关系:①生产者和生产者之间的互斥关系。②消费者和消费者之间的互斥关系。③生产者和消费者之间的互斥且同步的关系。有两种角色:①负责生产数据的生产者。②负责消费数据的消费者。有一个交易场所:①提供数据交易的可以短暂存储数据的内存——数据结构对象。
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。