一.信号量
1.1信号量的概述
信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负整数计数器,它被用来控制对公共资源的访问
编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量大于0时,则可以访问,否则将阻塞
信号量又称之为PV操作,P V原语是对信号量的操作,一次P操作使信号量使信号量sem-1,一次V操作使信号量sem+1,对于P操作,如果信号量的sem值小于等于0,则P操作就会阻塞,如果信号量的值大于0,才可以执行p操作进行减1
信号量主要用于进程或线程间的同步和互斥这两种情况
-
若用于互斥,几个进程(或线程)往往只设置一个信号量
-
若用于同步操作,往往会设置多个信号量,并且安排不同的初始值,来实现它们之间的执行顺序
信号量用于互斥
信号量用于同步
二 信号量操作
2.1 信号量初始化
1. #include <semaphore.h>
2. int sem_init(sem_t *sem,int pshared,unsigned int value);
3. 功能:创建一个信号量并初始化它的值
4. 参数: sem:信号量地址
pshared:等于0,信号量在线程间共享;不等于0,信号量在进程共享。
value:信号量的初始值。
5.返回值:成功返回0,失败返回-1;
2.2 信号量的P操作
1. #include<semaphore.h>
2. int sem_wait(sem_t *sem);
3. 功能:将信号量的值减1,若信号量的值小于等于0,此函数会引起调用者阻塞
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1
#include<semaphore.h>
2. int sem_trywait(sem_t *sem);
3. 功能:将信号量的值减1,若信号量的值小于等于0,则对信号量的操作失败,函数立即返回
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1
2.3 信号量的V操作
1. #include <semaphore.h>
2. int sem_post(sem_t *sem)
3. 功能:执行v操作,执行一次,信号量的值加1
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1
2.4 获取信号量的计数值
1. #include <semaphore.h>
2. int sem_getvalue(sem_t *sem,int *sval);
3. 功能:获取sem标识的信号量的值,保存在sval中
4. 参数:sem:信号量地址 sval:保存信号量值的地址
5. 返回值:成功返回0,失败返回-1
2.5 信号量的销毁
1. #include <semaphore.h>
2. int sem_destroy(sem_t *sem);
3. 功能:删除sem标识的信号量,
4. 参数:sem:信号量地址
5. 返回值:成功返回0,失败返回-1
三 信号量的使用
3.1 信号量实现互斥功能
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
// 通过信号量实现互斥操作
// 第一步:创建一个信号量
sem_t sem;
void printer(char *str)
{
// 第三步:执行p操作
// 由于使用信号量实现互斥,信号量初始值设置为1,则两个线程执行p操作
// 先执行p操作的线程继续执行,后执行p操作的先阻塞等待
sem_wait(&sem);
while(*str){
putchar(*str);
fflush(stdout);
str++;
sleep(1);
}
// 第四步:执行v操作
sem_post(&sem);
}
void *thr_fun1(void *arg)
{
char *str1 = "change";
printer(str1);
}
void *thr_fun2(void *arg)
{
char *str2 = "word";
printer(str2);
}
int main()
{
pthread_t th1,th2;
// 第二步:初始化信号量
sem_init(&sem,0,1);
if(pthread_create(&th1,NULL,thr_fun1,NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if(pthread_create(&th2,NULL,thr_fun2,NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
pthread_join(th1,NULL);
pthread_join(th2,NULL);
printf("\n");
// 第五步
sem_destroy(&sem);
return 0;
}
执行结果
3.2 信号量实现同步功能
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
// 通过信号量实现同步操作
// 第一步:创建两个信号量
sem_t sem_p,sem_g;
char ch = 'a';
void *thr_g(void *arg)
{
while(1)
{
// 第四步:执行p功能
sem_wait(&sem_g);
ch++;
sleep(1);
// 第六步:执行v操作
sem_post(&sem_p);
}
pthread_exit(0);
}
void *thr_p(void *arg) // 打印ch的值
{
while(1){
// 第三步执行p操作
sem_wait(&sem_p);
printf("%c",ch);
fflush(stdout);
// 第五步执行V操作
sem_post(&sem_g);
}
pthread_exit(0);
}
int main()
{
pthread_t th1,th2;
// 第二步初始化信号量
sem_init(&sem_p,0,1);
sem_init(&sem_g,0,0);
if(pthread_create(&th1,NULL,thr_p,NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if(pthread_create(&th2,NULL,thr_g,NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
pthread_join(th1,NULL);
pthread_join(th2,NULL);
printf("\n");
// 第五步,销毁信号量
sem_destroy(&sem_p);
sem_destroy(&sem_g);
return 0;
}