线程(进程)同步--信号量

linux中的信号量既可以用于线程间的同步又可以用于进程间的同步。
信号量实际上是一个非负的整数计数器,用来实现对公共资源的控制。在公共资源增加的时候,信号两的值增加;公共资源消耗的时候,信号量的值减少;只有当信号量的值大于大于0的时候,才能访问信号量所带表的公共资源。
ps:信号量在linux有posix接口和系统api接口,后者实在是太难记住,所以直接使用前者吧。

有关信号量的主要函数有信号量初始化函数sem_init(3)、信号量的销毁函数sem_destroy(1)、信号量的增加函数sem_post(1)以及信号量的减少函数sem_wait(1)。
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。

1. 信号量的初始化函数sem_init(3)

int sem_init(sem_t *sem, int pshared, unsigned int value);

  参数
    sem 指针,指向匿名信号量;
    value 参数指定信号量的初始值;
    pshared 参数指明信号量是由进程内线程共享:0是线程共享,非0是进程共享;
  返回值
    sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。

2. 信号量的增加函数sem_post(1)

sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的。

int sem_post(sem_t *sem);

  参数
    sem 指针,指向匿名信号量;
  返回值
    sem_post() 成功时返回 0;错误时,信号量的值没有更改,-1 被返回,并设置 errno 来指明错误。

3. 信号量的减少函数sem_wait(1)

sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。
也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,这信号量的值将减到1。
如果对一个值为0的信号量调用sem_wait(),这个函数就 会地等待直到有其它线程增加了这个值使它不再是0为止。

int sem_wait(sem_t * sem);

  参数
    sem 指针,指向匿名信号量;
  返回值
    sem_wait() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。

4. 信号量的销毁函数sem_destroy(1)

int sem_destroy(sem_t *sem);

  参数
    sem 指针,指向匿名信号量;
  返回值
    sem_wait() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。

好,下面来看个例子,生产者消费者

/*
	生产者消费者
	我的例子中有2个消费者,2个生产者,10个缓冲区来存放产品
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define buf_count 10
#define consumer_count 2
#define producer_count 2

int pos;
int cpos;
int buf[buf_count];
pthread_mutex_t buf_mutex,cbuf_mutex;
sem_t buf_empty,buf_full;

void* producer(void *arg)
{

	int start = *(int*)arg;
	int end = start + 10;
	while(start < end)
	{
		sem_wait(&buf_empty);
		pthread_mutex_lock(&buf_mutex);
		buf[pos] = start;
		printf("producer%u put buf[%d]:%d\n",pthread_self(),pos,buf[pos]);
		pos = (pos+1)%buf_count;
		pthread_mutex_unlock(&buf_mutex);
		sem_post(&buf_full);
		usleep(1);
		++start;
	}
}

void* consumer(void *arg)
{

	while(1)
	{
		sem_wait(&buf_full);
		pthread_mutex_lock(&cbuf_mutex);
		printf("\t consumer%u take buf[%d]:%d\n",pthread_self(),cpos,buf[cpos]);
		pthread_mutex_unlock(&cbuf_mutex);
		cpos = (cpos+1)%buf_count;
		usleep(50);
		sem_post(&buf_empty);
	}
}

int main()
{
	sem_init(&buf_full,0,0);
	sem_init(&buf_empty,0,10);
	pthread_mutex_init(&buf_mutex,NULL);
	pthread_mutex_init(&cbuf_mutex,NULL);

	pthread_t consumers[consumer_count];
	pthread_t producers[producer_count];

	int producerStart[producer_count];
	int pc = 0;
	while(pc < producer_count)
	{
		producerStart[pc] = pc * 10;
		++pc;
	}
	int i = 0;
	while(i < producer_count)
	{
		printf("main create producer%d\n",i);
		pthread_create(&producers[i],NULL,producer,(void*)&producerStart[i]);
		++i;
	}
	i = 0;
	while(i < consumer_count)
	{
		printf("main create consumer%d\n",i);
		pthread_create(&consumers[i],NULL,consumer,NULL);
		++i;
	}
	i = 0;
	while(i < producer_count)
	{
		pthread_join(producers[i],NULL);
		++i;
	}
	i = 0;
	while(i < consumer_count)
	{
		pthread_join(consumers[i],NULL);
		++i;
	}

	pthread_mutex_destroy(&buf_mutex);
	pthread_mutex_destroy(&cbuf_mutex);
	sem_destroy(&buf_full);
	sem_destroy(&buf_empty);
	return 0;
}

  

时间: 2024-07-30 18:53:18

线程(进程)同步--信号量的相关文章

线程进程,信号量,event事件,定时器,RLock,quene.Quene

cpu进程,核线程,都是并发几个 全局解释锁,多核cpu优势削弱 RLock用法与Lock一致,但是可以允许开启多个锁,但是也要关闭后,别的进程才能打开 信号量也是锁但是是一次可以进去几个. Seamaphore() 用法与Lock一致 Event好处是可以唤醒 事件# 是用于协调多个线程工作的,当一个线程要执行某个操作,需要获取另一个线程的状态# 你要给别人打电话 必须明确知道对方手机买好了# 作为客户端 要连接服务器 必须明确服务器已经启动了,那么作为启动服务器的一方 如何告知客户端?# 就

经典线程同步 信号量Semaphore

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> 前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数,使用很方便.下面是这几个函数的原型和使

线程间同步之信号量实现环形buf

一.概述: 信号量是一个非负整数的计数器,它通过计数器来实现多线程对临界资源的顺序访问,从而实现线程间的同步.它与进程间通信的信号量不同,进程间通信的信号量是一个信号量集,而线程间同步的信号量是一个信号.还有一点,就是对信号量的操作是原子的. 信号量与互斥锁的区别: (1).互斥锁的值只能是0或1,而信号量的值为非负整数. (2).互斥锁用与实现线程间的互斥,而信号量用于实现线程间的同步. (3).互斥锁的加锁和解锁必须由同一个线程分别对应使用,而信号量可以由一个线程得到,另一个线程释放. 下面

秒杀多线程第八篇 经典线程同步 信号量Semaphore

版权声明:本文为博主原创文章,未经博主允许不得转载. 阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> 前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore

linux网络编程-----&gt;线程同步--&gt;信号量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

线程同步---信号量(无名)

1. 有名信号量&无名信号量 在POSIX标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量只用于线程间的同步,有名信号量只用于进程间通信.信号量是属于POSIX:SEM的,不是属于POSIX:THR的,需要的文件头是<semaphore.h>.两者的共同点都是相当于计数器,用于限制多个进程对有限共享资源的访问 2.  相关函数 1)创建信号量 int sem_init (sem_t* sem, int pshared,unsigned int value); sem

转---秒杀多线程第八篇 经典线程同步 信号量Semaphore

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> 前面介绍了关键段CS.事件Event.互斥量Mutex在经典线程同步问题中的使用.本篇介绍用信号量Semaphore来解决这个问题. 首先也来看看如何使用信号量,信号量Semaphore常用有三个函数,使用很方便.下面是这几个函数的原型和使

用GCD线程组与GCD信号量将异步线程转换为同步线程

有时候我们会碰到这样子的一种情形: 同时获取两个网络请求的数据,但是网络请求是异步的,我们需要获取到两个网络请求的数据之后才能够进行下一步的操作,这个时候,就是线程组与信号量的用武之地了. 线程组用以监听线程的执行情况,而信号量就是用来将异步线程转化为同步线程. 以下是打印的数据: 2015-02-25 18:34:23.208 YXMWeather[265:8748] 请求1数据 2015-02-25 18:34:23.209 YXMWeather[265:8790] 1信号量结束 2015-

Linux线程同步---信号量

首先讲一下线程同步信号量的几个关键步骤! 1.定义并初始化信号量. (1) sem_t bin_sem; (2)  res = sem_init(&bin_sem,0,0); 详细步骤可以查看man帮助页面 2.使用信号量 (1) 信号量加1操作.sem_post(&bin_sem); (2) 信号量等待并减1操作.sem_wait(&bin_sem); 初始化后一般处于等待状态,执行某个操作后加1,而另个一个操作执行前进行等待操作.如果有多个线程,通常是一个线程进行加1操作,另外

线程同步——内核对象实现线程同步——信号量

1 /* 2 3 信号量内核对象 4 信号量与其它内核量相同,包含一个使用计数,除此之外还包含两个量. 5 一个最大资源计数和一个当前资源计数. 6 信号量规则如下: 7 如果当前资源计数大于0,那么信号量处于触发状态. 8 如果当前资源计数等于0,那么信号量处于未触发状态. 9 系统绝不会让当前资源计数变为负数. 10 当前资源计数绝不会大于最大资源计数. 11 12 下面我们看一下信号量的创建函数 13 HANDLE CreateSemaphore( 14 LPSECURITY_ATTRIB