`
lqy1987lqy
  • 浏览: 10915 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
最近访客 更多访客>>
社区版块
存档分类
最新评论

IPC 互斥锁和条件变量

    博客分类:
  • unp
 
阅读更多

在多线程或多进程间共享数据时,为了保证共享数据的正确性,同步是必不可少的。其中,互斥锁与条件变量是同步的重要组成部分, 互斥锁用来上锁, 条件变量用来等待。


1.1 互斥锁


互斥是指相互排斥(mutual exclusion)。互斥锁用于保护临界区(critical region), 以保证任何时刻只有一个线程(进程)在执行其中的代码,假设互斥锁由多个线程(进程),保护一个临界区的代码通常如下:

lock_the_mutex(...);
/* critical region */
unlock_the_mutex(...);

1.1.1 互斥锁初始化

Posix 互斥锁被声明为 pthread_mutex_t 数据类型的变量。可以用如下两种方法进行初始化。

  • 将互斥量初始化成常量值 PTHREAD_MUTEX_INITIALIZER 。linux 中 PTHREAD_MUTEX_INITIALIZER 的宏定义如下:
    #if __WORDSIZE == 64
    #define PTHREAD_MUTEX_INITIALIZER               \
        { { 0, 0, 0, 0, 0, 0, { 0, 0 } } }
    #ifdef __USE_GNU
    #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP                  \
        { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } }
    #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP                         \
        { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } }
    #define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP                   \
        { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } }
    #endif
    #else
    #define PTHREAD_MUTEX_INITIALIZER               \
        { { 0, 0, 0, 0, 0, { 0 } } }
    #ifdef __USE_GNU
    #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP                  \
        { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } }
    #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP                 \
        { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } }
    #define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP                   \
        { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } }
    #endif
    #endif
    
  • 如果互斥锁是通过动态分配的,那么我们在运行之时就不用使用第一种方式来初始化互斥锁,这时可以通过 pthread_mutex_init 函数来初始化。同时从上面的 PTHREAD_MUTEX_INITIALIZER 的宏定义可以看出,我们只要 将动态分配的变量全都初始化为0,也是行的,linux下可以用 bzero,标准 C 中有 memset。

1.1.2 互斥锁上锁和解锁

三个上锁或解锁的函数:

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mptr);

int pthread_mutex_trylock(pthread_mutex_t *mptr);

int pthread_mutex_unlock(pthread_mutex_t *mptr);

其中pthread_mutex_lock为阻塞函数,pthread_mutex_trylock 为非阻塞函数。对阻塞函数而言,如果互斥锁己被上锁则返回EBUSY错误。

 

1.2 条件变量

1.2.1 等待与信号发送

条件变量是类型为 pthread_cond_t 的变量。条件变量的相关操作函数如下:

#include<pthread.h>

int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);
int pthread_cond_signal(pthread_cond_t *cptr);

pthread_cond_wait(cond, mutex) 该函数原子地执行以下两个动作:

  • 给互斥锁 mutex 解锁。
  • 把调用线程投入睡眠, 直到另外某个线程就本条件变量cond调用pthread_cond_signal,pthread_cond_wait 在返回前重新给互斥锁 mutex 上锁。

给条件变量发送信号的代码大体如下:

struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    /* 维护本条件的各个变量 */
}var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER /*, ... */};

pthread_mutex_lock(& var.mutex);
/* set the condition as true */
pthread_cond_signal(& var.cond);
pthread_mutex_unlock(& var.mutex);
  

为了避免虚假唤醒(spurious wakeup), 测试条件并进入睡眠以等待该条件变为真 的代码如下:

pthread_mutex_lock(& var.mutex);
while (/* condition is false */ )
    pthread_cond_wait(& var.cond, & var.mutex);
/* change the condition */
pthread_mutex_unlock(& var.mutex);

为了避免上锁冲突将

/* producer */
pthread_mutex_lock(& nready.mutex);
if( nready.nready == 0)
    pthread_cond_signal(& nready.cond);
nready.nready++;
pthread_mutex_unlock(& nready.mutex);

/* consumer */
pthread_mutex_lock(& nready.mutex);
while( nready.nready == 0)
    pthread_cond_wait(& nready.cond, & nready.mutex);
nready.nready--;
pthread_mutex_unlock(& nready.mutex);

中的生产者的代码改为:

int dosignal;

pthread_mutex_lock(& nready.mutex);
dosignal = ( nready.nready == 0);
nready.nready++;
pthread_mutex_unlock(& nready.mutex);
if (dosignal)
    pthread_cond_signal(& nready.cond);

1.2.2 定时等待与广播

pthread_cond_signal 只唤醒等待在相应条件变量的一个线程,pthread_cond_broadcast 可以唤醒阻塞在相应条件变量上的所有线程。

#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cptr);
int pthread_cond_timedwait(pthread_cont_t *cptr, pthread_mutex_t *mptr, \
                           const struct timespec *abstime);

struct timespec{
    time_t tv_sec; /* seconds */
    long tv_nsec;  /* nanoseconds */
};


1.3 互斥锁和条件变量的属性

 

互斥锁属性的数据类型为 pthread_mutexattr_t, 条件变量属性的数据类型为 pthread_condattr_t。

互斥锁和条件变量及其性性初始化、摧毁函数和属性设置函数如下:

int pthread_mutex_init(pthread_mutex_t *mptr, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mptr);
int pthread_cond_init(pthread_cond_t *cptr, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cptr);

int pthread_mutexattr_init(pthread_mutexattr_t *mptr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *mptr);
int pthread_condattr_init(pthread_condattr_t *cptr);
int pthread_condattr_destroy(pthread_condattr_t *cptr);

int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *valptr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int value);
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *valptr);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int value);

/* return 0 if successed, else return errno */

 

分享到:
评论

相关推荐

    linux无亲缘关系进程间通信(互斥锁+条件变量+共享内存)

    总结来说,Linux无亲缘关系进程间通信的实现需要理解并熟练运用互斥锁、条件变量和共享内存的概念及API。这三个工具结合使用,可以构建出安全、高效的进程间同步机制,尤其适用于多进程协作处理大量共享数据的场景。...

    UNIX网络编程_卷2_进程间通信

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    linux进程间通信同步与互斥

    测试环境:64位ubuntu 13LTS 功能说明:使用互斥锁+条件变量+共享内存的方式实现进程(或线程)间的通信示例

    UNIX网络编程 第2卷 进程间通信

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程 第一卷+第二卷

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程-第2卷 程间通信 源代码

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    UNIX网络编程第一卷

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    IPC之睡眠理发师问题

    代码可能包含了一些特定的并发控制结构,如`pthread_mutex_t`(互斥锁)、`pthread_cond_t`(条件变量)等,以及如何使用`pthread`库来创建和管理线程。 总之,睡眠理发师问题是多线程编程中的经典案例,它展示了...

    UNIX环境高级编程_第二版中文

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名...

    线程间通信的定义及全局变量的方法

    为了解决线程间通信时出现的资源竞争问题,操作系统提供了几种同步机制,包括信号量(Semaphores)、互斥锁(Mutexes)和条件变量(Condition Variables)。它们允许我们在进行可能引起竞争的资源访问之前,先进行...

    UNIX网络编程,第2卷:进程间通信(第二版)

    本书从对Posix IPC和System V IPC的内部结构开始讨论,全面深入地介绍了4种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号量)、共享内存(匿名共享内存、具名共享内存...

    UNIX网络编程 第2卷 进程间通信 pdf

    本书从对Posix IPC和System V IPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区;...

    UNIX网络编程 第2版 第2卷 进程间通信.part1.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

    UNIX网络编程 第2版 第2卷 进程间通信.part3.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

    UNIX网络编程 第2版 第2卷 进程间通信.part2.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

    UNIX网络编程 第2版 第2卷 进程间通信.part4.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

    UNIX网络编程 第2版 第2卷 进程间通信.part5.rar

    本书从对PosixIPC和SystemVIPC的内部结构的综合讨论开始,具体阐述并比较了四种IPC形式:消息传递(管道、FIFO、消息队列)、同步(互斥锁、条件变量、读写锁、文件与记录锁、信号灯)、共享内存区(匿名共享内存区...

Global site tag (gtag.js) - Google Analytics