目录
信号量
信号量(semaphore)是一种常被用于多线程或多进程场景中的同步机制,用于保证多线程或多进程对共享数据的读/写操作是顺序的。
信号量的本质上是一个计数器,维护着一个 Value:
- 当 value > 0 时,信号量表示有可用的资源。
- 当 value < 0 时,信号量表示所有的资源都已经被占用了。
二元信号量
二元信号量(Binary Semaphore),即:计数器维护的 Value 只有 0 和 1 着两种可能,以此来实现互斥,所以也称为互斥信号量。
- 1:表示可以访问资源。
- 0:表示不能访问资源。
需要注意的是,二元信号量只能用于实现互斥,无法实现同步。如果需要实现线程间的同步,可以使用计数信号量(Counting Semaphore)。
另外,二元信号量的使用应尽量避免死锁问题的发生,即:避免出现多个线程相互等待的情况。
semaphore.h 库
C 语言可以使用 semaphore.h 库来使用二元信号量。
sem_init()
函数作用:用于创建并初始化一个二元信号量实体。
函数原型:
- sem 参数:指向一个信号量实体。
- pshared 参数:是一个类型标志位。
- 0:表示信号量是在多线程间共享的;
- non-0:表示信号量是在多进程间共享的。
- value 参数:表示信号量的初始值,只能为 0 或 1。
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 如果二元信号量的 Value 为 0,那么 sem_wait() 会将 Caller(调用者)阻塞,等待 Value 变 1 为止。
- 如果 Value 为 1,那么 sem_wait() 会将其减 1 并返回 0,表示自己拿到了信号;
- sem 参数:指向一个信号量实体。
sem_wait()
函数作用:
函数原型:
#include <semaphore.h>
int sem_wait(sem_t *sem);
- sem 参数:指向一个信号量实体。
sem_post()
函数作用:当线程完成了共享数据的访问后,应该使用 sem_post() 释放二元信号量,即:将 Value 变 1,让其他线程可以获取。
函数原型:
#include <semaphore.h>
int sem_post(sem_t *sem);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_THREADS 2
sem_t mutex;
void* thread_func(void* arg) {
int tid = *(int*) arg;
printf("Thread %d waiting...\n", tid);
/* 用一个互斥信号量来保护一个临界区。 */
sem_wait(&mutex); // 每个线程都先等待信号量变为正,然后进入临界区进行操作。
printf("Thread %d entered critical section.\n", tid);
sleep(1);
printf("Thread %d exiting critical section.\n", tid);
sem_post(&mutex); // 离开临界区并释放信号量。
pthread_exit(NULL);
}
int main() {
pthread_t threads[NUM_THREADS];
int thread_args[NUM_THREADS];
int i;
// Initialize the semaphore
sem_init(&mutex, 0, 1);
// Create the threads
for (i = 0; i < NUM_THREADS; i++) {
thread_args[i] = i;
pthread_create(&threads[i], NULL, thread_func, &thread_args[i]);
}
// Wait for the threads to finish
for (i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
// Destroy the semaphore
sem_destroy(&mutex);
return 0;
}
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47