接下来。来看一看信号量的使用。
概念部分:
信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。
函数接口部分:
#include <semaphore.h>
// 初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
// 信号量 P 操作(减 1)
int sem_wait(sem_t *sem);
// 以非阻塞的方式来对信号量进行减 1 操作
int sem_trywait(sem_t *sem);
// 信号量 V 操作(加 1)
int sem_post(sem_t *sem);
// 获取信号量的值
int sem_getvalue(sem_t *sem, int *sval);
// 销毁信号量
int sem_destroy(sem_t *sem);
信号量使用:
1、信号量实现线程互斥(不管有多少线程,只要是实现互斥,都是定义一个信号量并且初始化为1,所有的线程要执行的操作都是先p-》执行功能性代码-》v)
例子1:
// 信号量用于互斥实例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
sem_t sem; //信号量
void printer(char *str)
{
sem_wait(&sem);//减一,p操作
while(*str) // 输出字符串(如果不用互斥,此处可能会被其他线程入侵)
{
putchar(*str);
fflush(stdout);
str++;
sleep(1);
}
printf("\n");
sem_post(&sem);//加一,v操作
}
void *thread_fun1(void *arg)
{
char *str1 = "hello";
printer(str1);
}
void *thread_fun2(void *arg)
{
char *str2 = "world";
printer(str2);
}
int main(void)
{
pthread_t tid1, tid2;
sem_init(&sem, 0, 1); //初始化信号量,初始值为 1
//创建 2 个线程
pthread_create(&tid1, NULL, thread_fun1, NULL);
pthread_create(&tid2, NULL, thread_fun2, NULL);
//等待线程结束,回收其资源
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem); //销毁信号量
return 0;
}
2、信号量实现同步(有多少个线程就要有多少个信号量,一一对应,初始化信号量有一个为1,其余的都为0,为1的是第一个执行(将自己的信号量p-》执行功能代码-》v(下一个要执行的线程的信号量))
例子2:
// 信号量用于同步实例
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem_g,sem_p; //定义两个信号量
char ch = 'a';
void *pthread_g(void *arg) //此线程改变字符ch的值
{
while(1)
{
sem_wait(&sem_g);
ch++;
sleep(1);
sem_post(&sem_p);
}
}
void *pthread_p(void *arg) //此线程打印ch的值
{
while(1)
{
sem_wait(&sem_p);
printf("%c",ch);
fflush(stdout);
sem_post(&sem_g);
}
}
int main(int argc, char *argv[])
{
pthread_t tid1,tid2;
sem_init(&sem_g, 0, 0); // 初始化信号量为0
sem_init(&sem_p, 0, 1); // 初始化信号量为1
// 创建两个线程
pthread_create(&tid1, NULL, pthread_g, NULL);
pthread_create(&tid2, NULL, pthread_p, NULL);
// 回收线程
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
信号量的使用还算简单,但是信号量的使用绝不仅限于此,补充点其他内容。
信号量=无名信号量(信号量)+有名信号量,前边介绍的是无名信号量使用,那有名信号量怎末使用呢?
概念:同无名信号量,都是非负整数,有名信号量>0,说明可以往下执行,反之阻塞。
同步与互斥模型:同无名信号量
有名信号量和无名信号量区别:无名信号量一般用于线程间的同步与互斥,有名信号量一般用于进程间的同步于互斥。
函数接口:
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
//打开一个信号量,当信号量存在时使用:
sem_t *sem_open(const char *name, int oflag);
//创建并打开一个信号量,当信号量不存在时使用:
sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);
// 信号量 P 操作(减 1)
int sem_wait(sem_t *sem);
// 以非阻塞的方式来对信号量进行减 1 操作
int sem_trywait(sem_t *sem);
// 信号量 V 操作(加 1)
int sem_post(sem_t *sem);
//关闭一个信号量
int sem_close(sem_t *sem);
//删除信号量
int sem_unlink(const char *name);
例子3:有名信号量实现进程间互斥
例子4、有名信号量实现进程间同步