1. 信号量
(1)概念
信号量是非负整数计数器,表示当前可使用的公共资源的个数;主要用于进程或线程的同步或互斥。
信号量 > 0,则可访问公共资源,信号量;信号量 < 0,则阻塞。
(2)PV操作
对信号量的操作。P是信号量+1,V使信号量-1.
2. 信号量相关函数
(1)信号量的初始化、销毁
#include<semaphore.h>
int sem_init(sem_t* sem, int pshared, unsigned int value);
/*
功能:
用value初始化信号量sem的初始值
参数:
sem:信号量地址
pshared:
0:信号量在线程间共享;
非0:信号量中进程间共享;
value:信号量的初始值
返回值:
成功:0
失败:-1
*/
int sem_destroy(sem_t* sem);
/*
功能:
销毁信号量sem
参数:
sem:信号量地址
返回值:
成功:0
失败:-1
*/
(2)信号量P操作(-1)
#include<semaphore.h>
int sem_wait(sem_t* sem);
/*
功能:
将信号量sem减1。若信号量 = 0,则阻塞,直至信号量 > 0,进行减1操作。
参数:
sem:信号量地址。
返回值:
成功:0
失败:-1
*/
int sem_trywait(sem_t* sem);
/*
功能:
以非阻塞方式对信号量减1操作。
返回值:
若信号量 > 0, 则减1,并返回0;
若信号量 = 0,则直接返回-1,并将errno设置为EAGAIN
*/
int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout);
/*
功能:
限时abs_timeout对信号量减1操作。
返回值:
abs_timeout内信号量 > 0,则减1,并返回0。
超时则返回-1,并将errno设置为ETIMEDOUT。
*/
(3)信号量V操作(+1)
#include<semaphore.h>
int sem_post(sem_t* sem);
/*
功能:
将信号量+1,并唤醒等待的线程。
参数:
sem:信号量地址。
返回值:
成功:0
失败:-1
*/
(4)获取信号量的值
#include<semaphore.h>
int sem_getvalue(sem_t* sem, int* sval);
/*
功能:
获取信号量sem的值,保存在sval中。
参数:
sem:信号量地址;
sval:保存信号量值的地址;
返回值:
成功:0
失败:-1
*/
3. 信号量用于互斥
将之前的打印机程序由互斥锁控制访问改为信号量控制访问。
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<semaphore.h>
sem_t sem;
void printer(char* str) {
while (*str != '\0') {
putchar(*str);
fflush(stdout); // 刷新输出缓冲区
str++;
usleep(1000);
}
putchar('\n');
}
void* task1(void* arg) {
char* str = (char*)arg;
sem_wait(&sem); // 使用打印机前P操作
printer(str);
sem_post(&sem); // 使用打印机后V操作
return NULL;
}
void* task2(void* arg) {
char* str = (char*)arg;
sem_wait(&sem); // 使用打印机前P操作
printer(str);
sem_post(&sem); // 使用打印机后V操作
return NULL;
}
int main(int argc, const char* argv[]) {
pthread_t tid1, tid2;
char* str1 = "Hello";
char* str2 = "World";
sem_init(&sem, 0, 1); // 初始化信号量
pthread_create(&tid1, NULL, task1, (void*)str1);
pthread_create(&tid2, NULL, task2, (void*)str2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_destroy(&sem); // 销毁信号量
return 0;
}
运行结果: