信号量

信号量是相互排斥锁的升级版把相互排斥锁中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;
}

linux 线程同步(二)的更多相关文章

  1. 【转】 Linux 线程同步的三种方法

    线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...

  2. linux线程同步(1)-互斥量

    一.概述                                                   互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行 ...

  3. Linux线程同步之读写锁(rwlock)

    读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 和 ...

  4. linux线程(二)内存释放

    linux线程有两种模式joinable和unjoinable. joinable线程:系统会保存线程资源(栈.ID.退出状态等)直到线程退出并且被其他线程join. unjoinable线程:系统会 ...

  5. Linux线程同步

    1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...

  6. Linux 线程同步的三种方法(互斥锁、条件变量、信号量)

    互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...

  7. Linux线程同步:条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  8. linux线程同步(5)-屏障

    一.概述                                                    barrier(屏障)与互斥量,读写锁,自旋锁不同,它不是用来保护临界区的.相反,它跟条 ...

  9. linux线程同步(3)-读写锁

    一.概述                                                    读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...

随机推荐

  1. Less功能特性

    (1)变量 我们常常在 CSS 中 看到同一个值重复多次,这样难易于代码维护 const bgColor="skyblue"; $(".post-content" ...

  2. uploadify插件可选参数的详细介绍

    Uploadify 是一个JQuery插件,它协助你轻松简单的将一个或多个文件上传至你的网站.  它需要Flash控件和后台开发语言的支持,丰富的参数配置,同时也简单易用,让你轻松上手.      官 ...

  3. 在vue中场景,循环行,点击当前行编辑数据

    当前列表 点击编辑,行变为编辑框. <Row style="color:#999;margin-bottom:11px"> <Row style="ma ...

  4. js小结(一)

    想要的效果:比如说返回 25%  12.5% 33.33% 有几位小数就显示几位,就用 a=Math.round(a*100)/100 如果想要强制返还两位小数,就使用 a=a.toFixed(2); ...

  5. c语言中的 strcpy和strncpy字符串函数使用介绍

    1.strcpy函数 函数原型:char *strcpy(char *dst,char const *src)            必须保证dst字符的空间足以保存src字符,否则多余的字符仍然被复 ...

  6. Layui下拉选渲染

    下拉选渲染有很多方式,这个比较简单,记录一下: HTML代码如下: <div class="layui-input-inline"> <input type=&q ...

  7. Mysql 字符函数详解

    MySql 所有字符串函数函数详解 ASCII(str) 返回str最左边第一位字符的ASCII编码,如果str为空,则返回 0 .如果str为NULL,则返回NULL -- 只返回a的ASCII编码 ...

  8. Linux CentOS7.5静默安装Oracle11gR2

    网上有很多安装教程,但大多不够完整,参照了一些教程,实测安装成功,整理出来分享给大家! 一.官方最低要求配置 内存:1G(官方最低要求1G) 硬盘:40G(企业版安装所需4.29G和1.7G数据文件) ...

  9. 树莓派 -- oled

    硬件 SPI0,CE0 SPI Master Driver 设备树 arch\arm\boot\dts\bcm2710-rpi-3-b.dts &gpio { spi0_pins: spi0_ ...

  10. 版本控制git之五-标签管理 tags 标签 代码版本 如: v1.0

      版本控制git之五-标签管理 打标签 像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要. 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等). ...