线程同步——信号量

来源:互联网 发布:pc蛋蛋app源码 编辑:程序博客网 时间:2024/06/08 18:38

【信号量定义】

       信号量从本质上是一个非负整数计数器,通过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-5sem_t sem3;//1-0void *fun1(){int p;while (1){sem_wait(&sem1);//减1sem_wait(&sem3);//减1//生产p = add_list();printf("生产[%d]n", p);sem_post(&sem2);//加1sem_post(&sem3);//加1sleep(1);}}void *fun2(){int p;while (1){sem_wait(&sem2);//减1sem_wait(&sem3);//减1//消费p = del_list();if (p < 0){printf("无产品可消费!n");}else{printf("消费[%d]n", p);}sem_post(&sem1);//加1sem_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);}