<semaphore.h> 是一个 POSIX 标准定义的头文件,用于提供信号量(semaphore)的接口。信号量是用于线程或进程间同步的一种机制,可以控制访问共享资源的线程数目,广泛应用于多线程和多进程编程。
本文将详细介绍 <semaphore.h> 的数据类型、函数、以及示例。
1. 引入头文件
在使用信号量功能时,必须包含 <semaphore.h>:
#include <semaphore.h>2. 数据类型
sem_t
 
- 信号量的主要数据类型。
- 定义为一个结构体,用于存储信号量的当前值和相关信息。
- 可以用于进程间或线程间的同步。
3. 函数及用途
以下是 <semaphore.h> 中的主要函数:
(1) 初始化与销毁信号量
| 函数 | 描述 | 
|---|---|
| int sem_init(sem_t *sem, int pshared, unsigned int value); | 初始化一个信号量。 | 
| int sem_destroy(sem_t *sem); | 销毁一个信号量。 | 
- sem_init参数说明:- sem:指向信号量的指针。
- pshared:- 如果为 0,信号量用于线程间同步。
- 如果为非 0,信号量用于进程间同步(需要位于共享内存中)。
 
- value:信号量的初始值(代表资源数目)。
 
- 返回值:成功返回 0,失败返回-1。
(2) 信号量操作
| 函数 | 描述 | 
|---|---|
| int sem_wait(sem_t *sem); | 将信号量的值减 1。如果信号量值为 0,则阻塞直到信号量值大于 0。 | 
| int sem_trywait(sem_t *sem); | 尝试将信号量值减 1。如果信号量值为 0,不阻塞,返回错误。 | 
| int sem_post(sem_t *sem); | 将信号量的值加 1。如果有阻塞的线程,唤醒其中一个线程。 | 
| int sem_getvalue(sem_t *sem, int *sval); | 获取信号量的当前值。 | 
4. 示例
(1) 线程间的同步
以下是一个简单的生产者-消费者问题示例,演示如何使用信号量控制线程同步:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>#define BUFFER_SIZE 5int buffer[BUFFER_SIZE];
int count = 0;sem_t empty;  // 表示空位的信号量
sem_t full;   // 表示已占用位的信号量
pthread_mutex_t mutex;  // 保护共享资源的互斥锁void *producer(void *arg) {for (int i = 0; i < 10; i++) {sem_wait(&empty);             // 减少空位pthread_mutex_lock(&mutex);   // 进入临界区buffer[count++] = i;          // 放入数据printf("Produced: %d\n", i);pthread_mutex_unlock(&mutex); // 离开临界区sem_post(&full);              // 增加已占用位sleep(1);}return NULL;
}void *consumer(void *arg) {for (int i = 0; i < 10; i++) {sem_wait(&full);              // 减少已占用位pthread_mutex_lock(&mutex);   // 进入临界区int item = buffer[--count];   // 取出数据printf("Consumed: %d\n", item);pthread_mutex_unlock(&mutex); // 离开临界区sem_post(&empty);             // 增加空位sleep(2);}return NULL;
}int main() {pthread_t prod, cons;sem_init(&empty, 0, BUFFER_SIZE); // 初始化空位信号量sem_init(&full, 0, 0);            // 初始化已占用信号量pthread_mutex_init(&mutex, NULL); // 初始化互斥锁pthread_create(&prod, NULL, producer, NULL);pthread_create(&cons, NULL, consumer, NULL);pthread_join(prod, NULL);pthread_join(cons, NULL);sem_destroy(&empty);              // 销毁信号量sem_destroy(&full);pthread_mutex_destroy(&mutex);    // 销毁互斥锁return 0;
}
输出示例
Produced: 0
Consumed: 0
Produced: 1
Produced: 2
Consumed: 1
Consumed: 2
...
(2) 进程间的同步
信号量也可以在进程间共享,但需要设置 sem_init 的 pshared 参数为非 0,并将信号量存储在共享内存中。
5. 注意事项
-  线程间 vs 进程间信号量: - pshared为 0 时,信号量用于线程间同步。
- 为非 0 时,需要将信号量置于共享内存区域,用于进程间同步。
 
-  阻塞与非阻塞操作: - sem_wait会阻塞直到信号量值大于 0。
- sem_trywait不会阻塞,而是立即返回成功或失败。
 
-  信号量的销毁: - 在不再需要信号量时,必须调用 sem_destroy释放资源。
 
- 在不再需要信号量时,必须调用 
-  避免死锁: - 正确管理信号量和互斥锁的顺序,以避免线程或进程死锁。
 
6. 总结
<semaphore.h> 提供了信号量相关的功能,适用于多线程或多进程场景下的同步问题。通过使用 sem_t 数据类型及相关函数,开发者可以有效地控制对共享资源的访问,确保线程安全。