1.信号量,可拿停车和停车位来简单理解。首先,比如创建了一个大小为8的信号量psem(停车位),只有当信号量psem大于0时(有停车位),才可以访问资源(停车。同时,可以将将停车位上的车开出,增加停车为资源。比如8个停车位,占了5个,只剩下3个。此时,可清空一个停车位,让剩余的停车位数量变成4。
2.代码:
/*利用生产者和消费者模型,理解信号量*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
//创建一个互斥量
pthread_mutex_t mutex;
//创建两个信号量
sem_t psem,csem;
struct Node{
int num;
struct Node *next;
};
//头节点
struct Node * head = NULL;
void * producer(void *arg)
{
//不断的创建新节点,添加到链表中,模拟生产者
while(1)
{
sem_wait(&psem); //利用信号里判断是否可继续执行
pthread_mutex_lock(&mutex);
struct Node * newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->next = head;
newNode->num = rand() % 1000;
head = newNode;
printf("add node,num : %d,tid : %ld\n",newNode->num,pthread_self());
pthread_mutex_unlock(&mutex);
sem_post(&csem); //生产之后,增加信号csem的数量,让消费者可以消费
}
return NULL;
}
void * customer(void * arg)
{
while(1)
{
sem_wait(&csem); //利用信号量判断是否可继续执行
pthread_mutex_lock(&mutex);
//保存头节点
struct Node *temp = head;
head = head->next; //删除节点
printf("del node,num : %d,tid : %ld\n",temp->num,pthread_self());
free(temp);
//条件变量进行阻塞等待,直到收到可继续执行的条件变量。
pthread_mutex_unlock(&mutex);
sem_post(&psem); //增加生产者的信号量,告诉生产者可以继续生产,相当于给生产者空出一个可存放物品的位置
}
return NULL;
}
int main()
{
//初始化互斥量
pthread_mutex_init(&mutex,NULL);
//初始化信号量
sem_init(&psem,0,8);
sem_init(&csem,0,0);
//创建5个消费者和消费者线程
pthread_t ptid[5],ctid[5];
for(int i = 0;i < 5;i++)
{
pthread_create(&ptid[i],NULL,producer,NULL);
pthread_create(&ctid[i],NULL,customer,NULL);
}
//设置线程分离,方便线程在结束后,自动回收其资源
for(int i = 0;i < 5;i ++)
{
pthread_detach(ptid[i]);
pthread_detach(ctid[i]);
}
//阻塞进程
while(1)
{
sleep(100);
}
//销毁互斥量
pthread_mutex_destroy(&mutex);
//销毁信号量
sem_destroy(&psem);
sem_destroy(&csem);
//退出主线程,不会影响子线程
pthread_exit(NULL);
return 0;
}
3.运行结果:
4.总结:信号量相当于为动物园创建了一定数量的入口,没有一个线程访问时,动物园的入口数量就减少一个,当一个线程结束访问时,动物园的入口数量就恢复一个。只有当动物园的入口数量大于0时,其他线程才可以访问动物园,即访问资源,负责,处于阻塞等待状态。