一、信号量
信号量就是操作系统中所用到的PV原子操作,它广泛用于进程或线程间的同步与互斥。信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
PV原子操作主要用于进程或线程间的同步和互斥这两种典型情况。若用于互斥,几个进程(或线程)往往只设置一个信号量sem,如图1。
当信号量用于同步操作时,往往设置多个信号量,并安排不同的初始值来实现它们之间的顺序执行,它们的操作如图。
二、主要函数
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化sem操作
/*pshared参数指示此信号量是在进程的线程之间共享,还是在进程之间共享。如果pshared的值为0,则信号量在进程的线程之间共享,并且应该位于所有线程都可见的某个地址(例如,全局变量或在堆上动态分配的变量)。value即为sem的初始值*/
int sem_wait(sem_t *sem);//P操作、信号量大于0时信号量减1、等于0阻塞
int sem_trywait(sem_t *sem);//P操作、信号量大于0时信号量减1、等于0不会阻塞立即返回
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
/*sem_timedwait()与sem_wait()相同,只是abs_timeout指定了一个限制,如果不能立即执行减量,则调用应该阻止的时间量。abs_timeout参数指向一个结构,该结构指定自1970-01-01 00:00:00+0000(UTC)纪元以来的绝对超时(以秒和纳秒为单位)。
该结构定义如下:
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds [0 .. 999999999] */
};
*/
int sem_post(sem_t *sem);//V操作、信号量的值加1
int sem_getvalue(sem_t *sem, int *sval);//获取信号量的值
int sem_destroy(sem_t *sem);//销毁信号量
Link with -pthread.
三、线程间通信同步操作实例
功能简介:每隔1秒输出"张三 18"
/*########################################################################
# File Name: test_pthread_sig.c
# Author: tanyaduckal
# mail: 2295375354@qq.com
# Created Time: 2022年01月04日 星期二 17时24分40秒
########################################################################*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define CORVAL 1
#define NORVAL 0
#define ERRVAL -1
#define handle_error(LOG) do { perror(LOG); exit(EXIT_FAILURE); } while(0)
#define qDbug() do { printf("%d\n", __LINE__); } while(0)
#include<pthread.h>
#include<semaphore.h>
#include<unistd.h>
typedef struct argument{
char *name;
int age;
}ARG;
void *start_routine1(void *arg);
void *start_routine2(void *arg);
sem_t sem1;
sem_t sem2;
int main(int argc,char **argv){
if(ERRVAL == sem_init(&sem1, 0, 1))
handle_error("sem_init");
if(ERRVAL == sem_init(&sem2, 0, 0))
handle_error("sem_init");
pthread_t thread1, thread2;
ARG arg = {"张三", 18};
if(0 != pthread_create(&thread1, NULL, start_routine1, (void *)&arg))
handle_error("pthread_create");
if(0 != pthread_create(&thread2, NULL, start_routine2, (void *)&arg))
handle_error("pthread_create");
if(0 != pthread_join(thread1, NULL))
handle_error("pthread_join");
if(0 != pthread_join(thread2, NULL))
handle_error("pthread_join");
return 0;
}
void *start_routine1(void *arg){
while(1){
if(0 != sem_wait(&sem1))
handle_error("sem_wait");
printf("%s ", (*(ARG *)arg).name);
sleep(1);
if(0 != sem_post(&sem2))
handle_error("sem_post");
}
}
void *start_routine2(void *arg){
while(1){
if(0 != sem_wait(&sem2))
handle_error("sem_wait");
printf("%d\n", (*(ARG *)arg).age);
sleep(1);
if(0 != sem_post(&sem1))
handle_error("sem_post");
}
}