文章目录
- 前言
- 一、为什么要线程同步?
- 二、线程同步
- pthread_cond_init
- pthread_cond_destroy
- pthread_cond_wait、pthread_cond_signal和 pthread_cond_broadcast
- 三、示例代码
前言
上节课学习了线程互斥,这节课针对线程互斥内容在做进一步的补充和完善,学习线程同步的概念。
提示:以下是本篇文章正文内容,下面案例可供参考
一、为什么要线程同步?
上一章我们所讲的线程互斥有一个问题,虽然我们有互斥锁,但是当我们的临界资源条件不满足时,我们就需要不断重复申请锁和释放锁的过程,做无用功,浪费系统和cpu资源,所以,针对此问题,我们就引入了线程同步来解决。
线程同步其本质就是告诉其他线程什么时候我们的临界资源已经准备就绪,可以开始运行,如果没有准备就绪,那么就阻塞。 这样就能很大程度上节约我们的系统资源。
二、线程同步
pthread_cond_init
man 3 pthread_cond_init
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
该函数与pthread_mutex_init 使用类似,当pthread_cond是全局或静态变量时,可以使用PTHREAD_COND_INITIALIZER来进行初始化。
pthread_cond_destroy
该函数与pthread_mutex_init 使用类似,当pthread_cond是全局或静态变量时,不需要调用此函数进行销毁。
pthread_cond_wait、pthread_cond_signal和 pthread_cond_broadcast
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex)
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal和 pthread_cond_broadcast 这两个函数都是用与告诉需要被同步的线程:条件已经满足,(你)你们可以运行了。
它们俩的区别就是,pthread_cond_signal一次只能一个线程可以运行,而pthread_cond_broadcast则是可以一次若干个线程按次序运行。
pthread_cond_wait函数是用于判断条件是否满足,如果不满足,则阻塞。
三、示例代码
需要注意的是,cond也要配合mutex来进行使用,他们两个是很有关联的。
代码如下(示例):
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>
#define TNUM 5
volatile bool quit = false; //防止编译器过度优化
typedef void (*Func_t)(std::string, pthread_mutex_t *, pthread_cond_t *);
void ThreadFunc1(std::string name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
while (!quit)
{
pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
if (!quit/*临界资源条件判断*/)
std::cout << name << ": 查看 " << std::endl;
pthread_mutex_unlock(mutex);
}
}
void ThreadFunc2(std::string name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
while (!quit)
{
pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
if (!quit/*临界资源条件判断*/)
std::cout << name << ": 保存 " << std::endl;
pthread_mutex_unlock(mutex);
}
}
void ThreadFunc3(std::string name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
while (!quit)
{
pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
if (!quit/*临界资源条件判断*/)
std::cout << name << ": 读取 " << std::endl;
pthread_mutex_unlock(mutex);
}
}
void ThreadFunc4(std::string name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
while (!quit)
{
pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
if (!quit/*临界资源条件判断*/)
std::cout << name << ": 打印 " << std::endl;
pthread_mutex_unlock(mutex);
}
}
void ThreadFunc5(std::string name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
while (!quit)
{
pthread_mutex_lock(mutex);
pthread_cond_wait(cond, mutex);
if (!quit/*临界资源条件判断*/)
std::cout << name << ": 切换 " << std::endl;
pthread_mutex_unlock(mutex);
}
}
class Data
{
public:
Data(std::string name, Func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond)
: _name(name), _func(func), _mutex(mutex), _cond(cond)
{
}
public:
std::string _name;
Func_t _func;
pthread_mutex_t *_mutex;
pthread_cond_t *_cond;
};
void *Total(void *args)
{
Data *cont = (Data *)args;
cont->_func(cont->_name, cont->_mutex, cont->_cond);
delete cont;
return nullptr;
}
int main()
{
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_mutex_init(&mutex, nullptr);
pthread_cond_init(&cond, nullptr);
pthread_t tids[TNUM];
Func_t funcs[TNUM] = {ThreadFunc1, ThreadFunc2, ThreadFunc3, ThreadFunc4, ThreadFunc5};
for (int i = 0; i < TNUM; i++)
{
std::string name = "New thread ";
name += std::to_string(i + 1);
Data *cont = new Data(name, funcs[i], &mutex, &cond);
pthread_create(tids + i, nullptr, Total, (void *)cont);
}
int count = 10;
sleep(5);
while (count)
{
std::cout << "conut : " << count-- << " -----------" << std::endl;
pthread_cond_signal(&cond);
// pthread_cond_broadcast(&cond);
sleep(1);
}
quit = true;
pthread_cond_broadcast(&cond);
for (int i = 0; i < TNUM; i++)
{
pthread_join(tids[1], nullptr);
std::cout << "New thread " << i + 1 << " has quit." << std::endl;
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}