信号量
Linux 下有信号量的API有两个,一个是之前讲的System V IPC信号量,现在讨论的是POSIX的信号量。
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t* sem);
int sem_wait(sem_t* sem);
int sem_trywait(sem_t * sem);
int sem_post(sem_t* sem);
所有这些接口的第一个参数sem 都指向一个被操作的信号量。
sem_init 中, pshared参数指定信号量的类型。如果其值为0,那么信号量就是当前进程的局部信号量。否则就是多个进程共享的。value 表示信号量的初始值。
sem_destroy 函数可用于销毁一个信号量,以释放其占有的内核资源。如果销毁一个正在被其他线程等待的信号量,后果不可预知。
sem_wait 函数以原子操作将信号量减1。如果信号量值为0,那么sem_wait 阻塞,直到这个信号量具有非0 值。
sem_trywait 是sem_wait的非阻塞版本。
sem_post函数以原子操作将信号量加1。如果信号量大于0,正在调用sem_wait的函数阻塞的线程将被唤醒。
互斥锁
POSIX互斥锁是在线程同步中重要的工具,概念不在赘述。
POSIX互斥锁相关的函数主要有5个:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t* mutex,
const pthread_attr_t * mutex_attr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_trylock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread_mutex_t* mutex);
这些参数的第一个参数指向要操作的目标互斥锁。
pthread_mutex_init 函数用于初始化互斥锁, mutex_attr参数指定互斥锁的属性。如果它使用NULL,表示是用默认的属性。
pthread_mutex_destroy 函数用于销毁一个互斥锁,以释放被其占有的内核资源,销毁一个已经加锁的互斥锁将导致不可预知的后果。
pthread_mutex_lock 函数以原子操作的方式给互斥锁加锁。如果目标互斥锁被锁住,那么pthread_mutex_lock将被阻塞,直到互斥锁被解锁。
pthread_mutex_trylock函数是pthread_mutex_lock的非阻塞版本。它始终会立即返回,不管互斥锁被加锁还是没加锁。
pthread_mutex_unlock 函数以原子操作的方式给一个互斥锁解锁。如果此时有其他线程正在等待这个互斥锁,这些线程会获取到它。
条件变量
一般的互斥锁和条件变量一起使用。
#include <pthread.h>
int pthread_cond_init(pthread_cond_t* cond,
const pthread_condattr_t* cond_attr);
int pthread_cond_destroy(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
这些操作的第一个参数cond指向要操作的目标条件变量,条件变量的类型是pthread_cond_t。
pthread_cond_init 函数用于初始化条件变量。cond_attr参数指定条件变量的属性。
pthread_cond_destroy 函数用于销毁条件变量,释放内核资源。销毁一个正在被等待的条件变量将失败并返回EBUSY。
pthread_cond_broadcast 函数以广播的方式唤醒所有等待目标条件变量的线程。
pthread_cond_signal 用于唤醒一个等待目标条件变量的线程。至于那个线程被唤醒,这是线程调度策略的问题。
pthread_cond_wait 函数用于等待目标条件变量。 mutex参数是用于保护条件变量的互斥锁,以保证pthread_cond_wait操作的原子性。在调用pthread_cond_wait前,必须确保互斥量mutex已经加锁,否则将导致不可预知的后果。
pthread_cond_wait一般干了三件事:
1、给互斥锁解锁
2、把调用线程投入睡眠,直到另外某个线程就本条件调用signal。
3、然后,在返回前重新给互斥锁上锁(没有获得锁时一直阻塞在这里)
上面的函数成功返回0,失败返回错误码。
线程和信号
和进程一样,线程也可以设置自己的信号掩码。
#include <pthread.h>
#include <signal.h>
int pthread_sigmask(int how, const sigset_t* newmask,
sigset_t* oldmask);
由于进程中的所有线程共享该进程的信号。所以线程库将根据线程掩码觉得把信号发送给哪个具体的线程。
信号的处理函数在进程中的线程是共享的,一旦一个线程注册了新的信号处理函数,那么就会影响其他线程的执行,所以,一般我们在编程的时候都会有一个专门的线程来处理所有的信号。
在某个线程中调用sigwait来等待信号处理:
int sigwait(const sigset_t * set ,int* sig);
set表示要处理的信号集合,他们可以可以认为是主线程中的信号掩码。
sig 指向的整数用于存储该函数的返回的信号值。
读写锁
读写锁与互斥量类似,不过读写锁允许更高的并行性。互斥量要么是锁住状态,要么是不加锁状态,而且一次只有一个线程对其加锁。读写锁可以有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可用同时占有读模式的读写锁。读写锁也叫做共享-独占锁,当读写锁以读模式锁住时,它是以共享模式锁住的,当它以写模式锁住时,它是以独占模式锁住的。
LINUX 读写锁是写者优先
网友评论