目录
一、POSIX信号量
POSIX信号量(POSIX Semaphores)是一种进程间或线程间同步机制,它允许进程或线程以协调的方式访问共享资源或进行其他形式的同步。与System V信号量相比,POSIX信号量提供了更简单的接口和更好的可移植性,并且可以用于线程间同步。下面是对POSIX信号量主要操作的详细解释:
信号量的本质是一把计数器,申请信号的本质就是预定资源。信号量有P操作和V操作,PV来源于荷兰语中的"Passeren"(等待/通过)和"Verhogen"(增加),但在英文文献中,它们通常被简单地称为P(或Wait)和V(或Signal)。
初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
- sem:指向sem_t类型变量的指针,该变量将被初始化为信号量。sem_t 代表一个信号量。
- pshared:控制信号量的共享属性。如果pshared的值为0,则信号量用于同一进程的线程间的同步;如果pshared的值非0,则信号量用于不同进程间的同步。
- value:信号量的初始值。通常,这个值是非负的,表示可用的资源数量或可以同时进入临界区的线程数。
销毁信号量
int sem_destroy(sem_t *sem);
参数:
- sem:指向要销毁的信号量的指针。
这个函数会释放信号量所占用的资源。在调用此函数之前,所有使用该信号量的线程都应该已经退出或完成了对该信号量的等待。
等待信号量(等同于 P操作)
int sem_wait(sem_t *sem);
参数:
- sem:指向要等待的信号量的指针。
当信号量的值大于0时,sem_wait会原子地将信号量的值减1并立即返回;如果信号量的值为0,调用线程将被阻塞,直到信号量的值变为正数,此时将其值减1,然后sem_wait返回。通常用于保护临界区或等待资源变得可用。
发布信号量(等同于 V操作)
int sem_post(sem_t *sem);
参数:
- sem:指向要发布的信号量的指针。
这个函数会原子地将信号量的值加1。如果这导致信号量的值大于0,且有一个或多个线程在sem_wait调用中阻塞,那么这些线程中的一个将被唤醒以继续执行。这通常用于表示资源已被释放或临界区已退出。
注意:
- 使用POSIX信号量时,必须确保在进程或线程结束前销毁所有已初始化的信号量,以避免资源泄漏。
- 在使用信号量时,必须确保没有死锁或竞态条件的发生。
- 在多线程程序中,如果信号量被多个线程共享,则需要确保对这些信号量的访问是原子的,但幸运的是,sem_init、sem_destroy、sem_wait和sem_post等函数本身就是线程安全的。
- 当使用进程间共享的信号量时(即pshared非0),可能需要考虑额外的同步机制来确保进程能够正确访问和修改信号量的值。这通常涉及到使用进程间通信(IPC)机制,如UNIX域套接字、命名管道或共享内存等。然而,对于大多数应用而言,线程间同步是更常见的用例。
举例演示POSIX信号量的用法:
#include <iostream>
#include <semaphore.h>
#include <thread>
#include <unistd.h>
#include <chrono>
sem_t sem;
void Producer()
{
for (int i = 0; i < 5; i++)
{
sem_wait(&sem); // 等待信号量
std::cout << "Producer produced item : " << i << std::endl;
sem_post(&sem);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产耗时
}
}
void Consumer()
{
for (int i = 0; i < 5; i++)
{
sem_wait(&sem);
std::cout << "Consumer consumed item " << i << std::