线程同步——信号量

【信号量定义】

       信号量从本质上是一个非负整数计数器,通过PV原子操作来达到控制公共资源的访问的目的。PV原子操作是对整数计数器信号量sem的操作。一次P操作使sem减1,而一次V操作使sem加1。当信号量sem的值大于等于0时,该进程(或线程)具有公共资源的访问权限;相反,当信号量sem的值小于0时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0为止。

       PV原子操作主要用于进程或线程间的同步和互斥这两种典型情况。若用于互斥,几个进程(或线程)往往只设置一个信号量sem;当信号量用于同步时,往往设置多个信号量,并安排不同的初始值来实现它们之间的顺序执行。

 

【相关函数】

(1)sem_init()用于创建一个信号量,并初始化它的值

     头文件:#include <semaphore.h>

     函数原型:int sem_init(sem_t *sem, int pthread, unsigned int value)

     函数传入值:sem:信号量指针

                           pthread:决定信号量能否在几个进程间共享。由于目前Linux还没有实现进程间共享信号量,所以这个值只能是0,表示这个信号量是当前进程的局部信号量。(进程间信号量共享可通过semget()等函数实现)

                           value:信号量初始化值

     函数返回值:成功返回0,失败返回-1

(2)P操作:sem_wait()对信号量的值减1,如果当前信号量为0,则函数堵塞,知道信号量大于等于1,才返回并将信号量的值减1

                  sem_trywait()也相当于P操作,但其不会阻塞而是立即返回。

(3)V操作:sem_post()对信号量的值加1,同时发出信号来唤醒等待的进程

(4)sem_getvalue()用于得到信号量的值

(5)sem_destroy()用于删除信号量

     函数(2)—(5):

            头文件:#include <pthread.h>

            函数传入值:sem_t *sem:信号量指针

            函数返回值:成功返回0,失败返回-1

 

【代码示例】

       利用信号量实现生产消费,最多生产5个,最多消费5个

/****************************
*信号量,最多生产5个,最多消费5个
****************************/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

typedef struct nList
{
	int sum;
	struct nList *next;
}product;

product *head = NULL;
product *tail = NULL;
product *new = NULL;

sem_t sem1;//5-0 
sem_t sem2;//0-5
sem_t sem3;//1-0

void *fun1()
{
	int p;
	while (1)
	{
		sem_wait(&sem1);//减1
		sem_wait(&sem3);//减1
		//生产
		p = add_list();

		printf("生产[%d]n", p);

		sem_post(&sem2);//加1
		sem_post(&sem3);//加1
		
		sleep(1);
	}
}

void *fun2()
{
	int p;
	while (1)
	{
		sem_wait(&sem2);//减1
		sem_wait(&sem3);//减1
		//消费
		p = del_list();

		if (p < 0)
		{
			printf("无产品可消费!n");
		}
		else
		{
			printf("消费[%d]n", p);		
		}

		sem_post(&sem1);//加1
		sem_post(&sem3);//加1		
	}
}

/*****************************
*函数功能:向链表添加结点
*输入参数:(product *)head:链表头结点
*输出参数:(int)
	(1)-1:添加失败
	(2)>0:添加成功,返回节点数据
*****************************/
int add_list()
{
	int n;
	product *p = head;

	srand((unsigned)time(NULL));

	new = (product *)malloc(sizeof(product));
	if (new == NULL)
	{
		perror("malloc");
		return -1;
	}

	new->sum = rand()0+1;
	n = new->sum;
	
	if (head == NULL)
	{
		head = new;
	}
	else
	{
		tail->next = new;
	}
	tail = new;
	tail->next = NULL;
	return n;
}

/*****************************
*函数功能:从链表删除结点
*输入参数:(product *)head:链表头结点
*输出参数:(int)
	(1)-1:删除失败
	(2)>0:删除成功,返回节点数据
*****************************/
int del_list()
{
	int n;
	product *p = head;

	if (head == NULL)
	{
		return -1;
	}
	else 
	{
		head = head->next;
		n = p->sum;
		free(p);
		p = NULL;
		return n;
	}
}

int main()
{
	pthread_t tid1, tid2;
	int ret;

	//信号量初始化
	ret = sem_init(&sem1, 0, 5);
	if (ret < 0)
	{
		perror("sem_init");
		exit(1);
	}
	ret = sem_init(&sem2, 0, 0);
	if (ret < 0)
	{
		perror("sem_init");
		exit(1);
	}
	ret = sem_init(&sem3, 0, 1);
	if (ret < 0)
	{
		perror("sem_init");
		exit(1);
	}

	ret = pthread_create(&tid1, NULL, fun1, NULL);
	if (ret < 0)
	{
		perror("pthread_create");
		exit(1);
	}
	pthread_create(&tid2, NULL, fun2, NULL);
	if (ret < 0)
	{
		perror("pthread_create");
		exit(1);
	}

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	sem_destroy(&sem1);
	sem_destroy(&sem2);
}


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值