美文网首页
多线程同步之 POSIX 同步

多线程同步之 POSIX 同步

作者: 小pb | 来源:发表于2019-11-04 11:26 被阅读0次

    信号量

    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 读写锁是写者优先

    相关文章

      网友评论

          本文标题:多线程同步之 POSIX 同步

          本文链接:https://www.haomeiwen.com/subject/eqprbctx.html