linux学习笔记(22)线程同步——线程信号量
线程信号量
线程信号量 vs 进程信号量
主要区别:
特性 | 进程信号量 | 线程信号量 |
头文件 | #include | #include |
创建 | semget() + 复杂初始化 | sem_init() |
使用 | semop() | sem_wait() / sem_post() |
范围 | 系统范围 | 进程内部 |
线程信号量的三个核心函数
1. sem_init() - 初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
- sem: 信号量指针
- pshared: 0表示线程间共享,非0表示进程间共享
- value: 信号量初始值
2. sem_wait() - P操作(等待)
int sem_wait(sem_t *sem); // 阻塞等待 int sem_trywait(sem_t *sem); // 非阻塞尝试
3. sem_post() - V操作(释放)
int sem_post(sem_t *sem); // 释放信号量
简单的线程信号量例子
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t semaphore; // 定义信号量
int shared_data = 0;
void* worker(void* arg) {int id = *(int*)arg;printf("线程%d: 等待信号量...\n", id);sem_wait(&semaphore); // P操作printf("线程%d: 获得信号量,开始操作共享数据\n", id);shared_data++;sleep(2); // 模拟工作printf("线程%d: 共享数据 = %d\n", id, shared_data);sem_post(&semaphore); // V操作printf("线程%d: 释放信号量\n", id);return NULL;
}
int main() {pthread_t t1, t2;int id1 = 1, id2 = 2;// 初始化信号量,初始值为1(二进制信号量)sem_init(&semaphore, 0, 1);printf("创建两个线程...\n");pthread_create(&t1, NULL, worker, &id1);pthread_create(&t2, NULL, worker, &id2);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("最终共享数据: %d\n", shared_data);// 销毁信号量sem_destroy(&semaphore);return 0;
}
创建两个线程...
线程1: 等待信号量...
线程1: 获得信号量,开始操作共享数据
线程2: 等待信号量... ← 线程2在这里阻塞等待
线程1: 共享数据 = 1
线程1: 释放信号量
线程2: 获得信号量,开始操作共享数据
线程2: 共享数据 = 2
线程2: 释放信号量
最终共享数据: 2
生产者--消费者问题:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0, out = 0;
// 信号量定义
sem_t empty; // 空槽位数量
sem_t full; // 已使用槽位数量
sem_t mutex; // 二进制信号量,保护缓冲区
void* producer(void* arg) {int item = 0;while (1) {// 生产一个项目sleep(1); // 模拟生产时间sem_wait(&empty); // 等待空槽位sem_wait(&mutex); // 进入临界区// 将项目放入缓冲区buffer[in] = item++;printf("生产者生产: %d, 位置: %d\n", buffer[in], in);in = (in + 1) % BUFFER_SIZE; sem_post(&mutex); // 离开临界区sem_post(&full); // 增加已使用槽位}return NULL;
}
void* consumer(void* arg) {while (1) {sem_wait(&full); // 等待有数据的槽位sem_wait(&mutex); // 进入临界区// 从缓冲区取出项目int item = buffer[out];printf("消费者消费: %d, 位置: %d\n", item, out);out = (out + 1) % BUFFER_SIZE;sem_post(&mutex); // 离开临界区sem_post(&empty); // 增加空槽位sleep(2); // 模拟消费时间}return NULL;
}int main() {// 初始化信号量sem_init(&empty, 0, BUFFER_SIZE); // 初始有5个空位sem_init(&full, 0, 0); // 初始没有数据sem_init(&mutex, 0, 1); // 二进制信号量pthread_t prod, cons;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);sem_destroy(&mutex);return 0;
}