信号量

信号量是相互排斥锁的升级版把相互排斥锁中1变成了n。举个简单的样例:如果如今有10个人,有一部手机。这10个人都竞争来使用手机打电话这就是相互排斥锁。对于信号量,如今可能是有4部手机,这10个人都竞争来使用手机打电话。相比相互排斥锁信号量由1变成了4。信号量相也就是操作系统中pv操作,它广泛应用进程或者线程间的同步与相互排斥。

相关库函数介绍

#include <semaphore.h>//所需头文件
//初始化信号量sem初始化的时候能够指定信号量的初始值,以及能否够在多进程间共享value表示要信号量初始值,pshared表示是否再多进程之前共享。 0表示不在多进程间
共享,非0表示在多进程之间共享详细能够man sem_init
//成功返回0,出错返回-1
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem)//相当于p操作
int sem_try_wait(sem_t *sem)//相当于p操作。在信号量值大于0时都能将信号量的值减一,与上面sem_wait的差别是,在信号值小于0时
int sem_post(sem_t *sem)//相当于v操作
int sem_getvalue(sem_t *sem)//用于得到信号量的值
int sem_destory(sem_t *sem) //释放信号量
 

信号量实例:生产者消费值

#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFSIZE 10
int buf[BUFSIZE];
sem_t consumer_sem,producer_sem;
void *consumer(void *arg)
{
int c=0;
while(1)
{
sem_wait(&consumer_sem);//開始消费consumer_sem值减一
printf("consumer %d: %d\n",c,buf[c]);//消费数据
c++;
c=c%BUFSIZE;
sleep(1);//睡眠1s
sem_post(&producer_sem);//producer_sem值加1
}
}
void *producer(void *arg)
{
int p=0;
while(1)
{
sem_wait(&producer_sem);//開始生产producer_sem值减一
buf[p]=rand() % 1000 + 1;//生产数据
printf("producer %d: %d\n",p,buf[p]);
p++;
p=p%BUFSIZE;
sem_post(&consumer_sem);//consumer_sem值加1 }
} int main()
{ sem_init(&consumer_sem,0,0);
sem_init(&producer_sem,0,BUFSIZE); pthread_t pid,cid;
pthread_create(&pid,NULL,producer,NULL);
pthread_create(&cid,NULL,consumer,NULL); pthread_join(pid, NULL);
pthread_join(cid, NULL);
sem_destroy(&consumer_sem);
sem_destroy(&producer_sem);
return 0; }

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

条件变量

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包含两个动作:一个线程等待"条件变量的条件成立"而挂起;还有一个线程使"条件成立"(给出条件成立信号)。

为了防止竞争,条件变量的使用总是和一个相互排斥锁结合在一起。

条件变量类型为 pthread_cond_t

相关库函数简单介绍

#include<pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);//条件变量的资源释放
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);//条件变量的初始化
 
#include<pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *mutex,
const struct timespec *abstime);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
//等待某个条件是否成立。对于timewait()函数除了等待以外。能够设置一个时长。
int pthread_cond_signal(pthread_cond_t *cond);//种情况是仅仅有一个线程收到后运行动作。 //活动线程仅仅须要唤醒第一个正在睡眠的线程。如果您仅仅对队列加入了一个工作作业。 那么仅仅须要唤醒一个工作程序线程(再唤醒其他线程是不礼貌的! )
int pthread_cond_broadcast(pthread_cond_t *cond);//通过广播的形式发给子线程消息。子线程竞争运行。

不管哪种等待方式,都必须和相互排斥锁结合,以防止多个线程同一时候请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件,且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列曾经,mutex保持锁定状态。并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被又一次加锁,以与进入pthread_cond_wait()前的加锁动作相应。

#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h> struct msg {
struct msg *next;
int num;
}; struct msg *head;
/* 条件变量 */
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *consumer(void *p)
{
struct msg *mp;
while(1)
{
pthread_mutex_lock(&lock);
/* pthread_cond_wait(&has_product, &lock);
* 1.堵塞等待has_product被唤醒。
* 2.释放相互排斥锁。 pthread_mutex_unlock(&lock)
* 3.当被唤醒时。解除堵塞,而且又一次去申请获得相互排斥锁 pthread_mutex_lock(&lock)
*/
while (head == NULL)
pthread_cond_wait(&has_product, &lock);//等待 mp = head;
head = mp->next;
pthread_mutex_unlock(&lock);
printf("Consume %d\n", mp->num);
free(mp);
sleep(rand() % 5);
}
} void *producer(void *p)
{
struct msg *mp;
while(1)
{
mp =(struct msg *)malloc(sizeof(struct msg));
mp->num = rand() % 1000 + 1;
printf("Produce %d\n", mp->num);
pthread_mutex_lock(&lock);
mp->next = head;
head = mp;
pthread_mutex_unlock(&lock);
/* pthread_cond_broadcast(&has_product) 唤醒等待队列上的全部线程*/
//发送信号,告诉消费者有产品了
pthread_cond_signal(&has_product);
sleep(rand() % 5);
}
} int main(int argc, char *argv[])
{
pthread_t pid, cid;
srand(time(NULL));
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}

最新文章

  1. nodejs 批量修改、删除
  2. javascript for循环练习
  3. Maven学习(七)仓库
  4. Navi.Soft30.框架.WinForm.开发手册
  5. 求前几日的平均值用obj.reduce()方法
  6. (转)Eclipse快捷键大全,导包快捷键:ctrl+Shift+/
  7. Linux系统编程(32)—— socket编程之TCP服务器与客户端
  8. SQL从入门到基础 - 07 抑制重复数据
  9. Unix/Linux环境C编程入门教程(30) 字符串操作那些事儿
  10. Oracle EBS-SQL (SYS-23):用户权限查询.sql
  11. hdu3001(状压dp)
  12. Android kxml解析WBXML
  13. Golang适合高并发场景的原因分析
  14. Hadoop Compatibility in Flink
  15. vue--存储
  16. apicloud模块开发知识点
  17. c#,asp.net 开发 app 学习资料整理
  18. process概念
  19. VAE--就是AutoEncoder的编码输出服从正态分布
  20. workstation vmware 制作vm模板

热门文章

  1. mac vim编辑器常用操作快捷方式
  2. ORACLE中的游标Cursor总结
  3. windows mac配置host方法
  4. CSU——2161: 漫漫上学路 最短路
  5. &lt;Redis&gt; 入门五 持久化RBD/AOF
  6. Layui表格之多列合并展示
  7. 配置Django+mysql+pydev(x64)
  8. 集训第四周(高效算法设计)B题 (二分查找优化题)
  9. First C program
  10. hadoop_exporter+prometheus