目录
条件变量本身不是锁 ! 但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。
pthread_cond_t 类型用于定义条件变量。pthread_cond_t cond;
pthread_cond_init 函数
int pthread_cond_init ( pthread_cond_t * restrict cond ,const pthread_condattr * restrict attr );参 1 :需要初始化的条件变量参 2 : attr 表条件变量属性,通常为默认值,传 NULL 即可
初始化有两种方法:
1. 动态初始化: pthread_cond_init ( & cond , NULL )2. 静态初始化: pthread_cond_t cond = PTHREAD_COND_INITIALIZER ;
pthread_cond_wait 函数
阻塞等待一一个条件变量
int pthread_cond_wait ( pthread_cond_t * restrict cond ,pthread_mutex_t * restrict mutex );参 1 :已经初始化号的条件变量,如果条件不满足,则一直阻塞等待参 2 :一把已加锁的互斥锁,解锁已加锁的 mutex ,等价 pthread_mutex_unlock ( & mutex )参1 、参 2 执行时是原子操作。(也就阻塞时,会继续操作解锁,中途不会被中断)函数返回 return 前:当条件变量必须满足,同步解除阻塞并重新给互斥量加pthread_mutex_lock ( & mutex )
pthread_cond_signal函数
唤醒等待在该条件变量上的一个线程
pthread_cond_broadcast函数
唤醒等待在该条件变量上的所有线程
int pthread_cond_signal ( & cond );参 1 :已经初始化好的条件变量
例程:生产-消费者模型代码
- #include
- #include
- #include
- #include
- #include
- /*链表作为公享数据,需被互斥量保护*/
-
- #define SIZE 100
-
- int repository[SIZE]={0};//定义仓库大小,并初始化为0
-
- /*静态初始化一个条件变量和一个互斥量*/
- pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
- pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
- int empty_repository(int arr[])
- {
- int i,sum=0;
- for(i=0;i
- {
- sum += arr[i];
- }
- return sum;
- }
-
- int fill_repository(int arr[])
- {
- int i,sum;
- for(i=0;i
- {
- if(arr[i]==0)
- {
- arr[i]= rand() % 1000 + 1;
- printf("-------fill a[%d]=%d\n",i,arr[i]);
- return arr[i];
- }
- }
- return -1;
- }
-
- int del_repository(int arr[])
- {
- int i,temp;
- for(i=SIZE;i>=0;i--)
- {
- if(arr[i]!=0)
- {
- temp=arr[i];
- printf("-------del a[%d]=%d\n",i,arr[i]);
- arr[i]= 0;
- return temp;
- }
- }
- return -1;
- }
-
- void *consumer(void *p)
- {
- for (;;)
- {
- int ret=pthread_mutex_lock(&lock);
- if(ret !=0)
- {
- printf("consumer mutex_lock err:%s\n",strerror(ret));
- }
- while (!empty_repository(repository))
- {
- //如果条件不满足,释放锁,并阻塞在此处
- //如果条件满足,重新加锁,并解除阻塞,进行循环条件判断
- printf("cond_wait test mask\n");
- pthread_cond_wait(&has_product, &lock);
- }
- //模拟消费掉一个产品
- ret=del_repository(repository);
- if(ret==-1)
- {
- printf("del_repository() err\n");
- pthread_exit(NULL);
- }
- pthread_mutex_unlock(&lock);
- printf("-Consume %lu---Produce id=%d\n", pthread_self(), ret);
-
- sleep(rand() % 5);
- }
- }
-
- void *producer(void *p)
- {
- for (; ;)
- { //sleep(5),为验证consumer线程中的,pthread_cond_wait()会进行解锁+阻塞功能
- sleep(5);
- //生产者拿锁成功,再生产产品
- int ret=pthread_mutex_lock(&lock);
- if(ret !=0)
- {
- printf("producer mutex_lock() err:%s\n",strerror(ret));
- pthread_mutex_unlock(&lock);
- break;//跳出循环
- }
- //模拟生产一个产品
- ret=fill_repository(repository);
- if(ret==-1)
- {
- printf("fill_repository() err\n");
- pthread_mutex_unlock(&lock);
- break;
- // pthread_exit(NULL);//生产仓库满后,无法继续生产,退出生产线程
- }
- pthread_mutex_unlock(&lock);
- printf("-producer %lu---Produce id=%d\n", pthread_self(), ret);
- pthread_cond_signal(&has_product); //条件满足了,通知等待条件变量has_product的线程
- usleep(100000);
- }
- }
-
- int main(int argc, char *argv[])
- {
- pthread_t tid01, tid02,tid03;
- srand(time(NULL));
- pthread_create(&tid01, NULL, producer, NULL);
- pthread_create(&tid02, NULL, consumer, NULL);
- // pthread_create(&tid03, NULL, consumer, NULL);
- pthread_join(tid01, NULL);
- pthread_join(tid02, NULL);
- // pthread_join(tid03, NULL);
-
- return 0;
- }
2. 信号量
信号量,是相对折中的一
-
种处理方式,既能保证同步,数据不混乱,又能提高线程并发。
由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。
主要函数
sem_init
函数
sem_destroy
函数
sem_wait
函数
sem_trywait
函数
sem_timedwait
函数
sem_post
函数
以上
6
个函数的返回值都是
:
成功返回
0
,失败返回
-1
, 同时设置
errno
。
(
注意,它们没有
pthread
前缀
)
sem_t
类型
,
本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节
(
类似于使用文件描述符
)
。
sem_tsem;
规定信号量
sem
不能
<0
头文件
信号量基本操作
sem_wait: 1.
信号量大于
0
,则信号量
-- (
类比
pthread_mutex_lock)
。
2.信号量等于0
时,再次调用会造成线程阻塞。
对应
sem_post :
将信号量
++
,同时唤醒阻塞在信号量上的线程
(
类比
pthread_mutex_unlock)
但,由于
sem
的实现对用户隐藏,所以所谓的
++. --
操作只能通过函数来实现,而不能直接
++
、
-
符号信号量的初值,决定了占用信号量的线程的个数。
sem_init
函数
初始化信号量
int
sem_init
(
sem_t
*
sem
,
int
pshared
,
unsigned int
vale
)
参
1
:
sem
已定义的信号量
参
2
:
pshared
0
用于线程间同步
1
用于进程间同步
参
3
:
vale N
值,指定同时能够访问的线程数
sem_destroy
函数
销毁信号量
int sen_destroy(sem_t *sem);
sem_wait
函数
信号量减减操作
(
类似加锁
)
int
sem_wait
(
sen_t
*
sem
);
sem_post
函数
信号量加加操作
(
类似解锁
)
int
sem_post
(
sen_t
*
sem
);
sem_timedwait 函数
限时尝试对信号量加锁
int
sem_timedwait
(
sem_t
*
sem
,
const struct
timespec
*
abs_timeout
);
参
2
:
abs_timeout
采用的是绝对时间(
1970
年
1
月
1
日
0
时
0
分
0
秒)。
比如定时
1
秒
:
time_t cur
=
time
(
NULL
);
获取当前时间
struct
timespec t
;
定义
timespec
结构体变量
t
t
.
tv_sec
=
cur
+
1
;
定时
1
秒。
t
.
tv_nsec
=
t
.
tv_sec
+
100
;
sem_timedwait
(
&
sem
,
&
t
);
传参
-
相关阅读:
基于遗传算法的水力发电厂的优化(Matlab代码实现)
Esbuild Bundler HMR
网络协议--TCP连接的建立与终止
流程自动化(RPA)的好处有哪些?
NumPy简单学习(需要结合书本)
Caldera(二)高级实战
Jupyter Notebook快速上手
开发小程序插件如何实现盈利?
Java刷题时常用的标准库数据结构和相应操作
满级大牛 HuaWei 首次出这份 598 页【网络协议全彩手册】,建议大家收藏
-
原文地址:https://blog.csdn.net/qq_59947178/article/details/127656787