zoukankan      html  css  js  c++  java
  • Linux IPC 同步(一):互斥锁 条件变量

    线程范围:

    同一个进程内的多个线程访问一些全局变量时,需要保护好临界区,保证不产生脏数据

    Linux 中的互斥锁

    #include <pthread.h>
    pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    互斥锁属性设置:

    #include <pthread.h>
    int pthread_mutexattr_init(pthread_mutexattr_t *attr);
    int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
    int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
    int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind);
    
    /* copy from glibc -2.17 */
    /* Mutex attribute data structure.  */
    struct pthread_mutexattr
    {
      /* Identifier for the kind of mutex.
         Bit 31 is set if the mutex is to be shared between processes.
         Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
         the type of the mutex.  */
      int mutexkind;
    };

    互斥锁类型:

    如果互斥锁类型为 PTHREAD_MUTEX_NORMAL,则不提供死锁检测。尝试重新锁定互斥锁会导致死锁。如果某个线程尝试解除锁定的互斥锁 未锁定 或 不是由该线程锁定,则将产生不确定的行为。

    如果互斥锁类型为 PTHREAD_MUTEX_ERRORCHECK,则会提供错误检查。如果某个线程尝试重新锁定的互斥锁已经由该线程锁定,则将返回错误。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
    如果互斥锁类型为 PTHREAD_MUTEX_RECURSIVE,则该互斥锁会保留锁定计数这一概念。线程首次成功获取互斥锁时,锁定计数会设置为 1。线程每重新锁定该互斥锁一次,锁定计数就增加 1。线程每解除锁定该互斥锁一次,锁定计数就减小 1。 锁定计数达到 0 时,该互斥锁即可供其他线程获取。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
    如果互斥锁类型是 PTHREAD_MUTEX_DEFAULT,则尝试以递归方式锁定该互斥锁将产生不确定的行为。对于不是由调用线程锁定的互斥锁,如果尝试解除对它的锁定,则会产生不确定的行为。如果尝试解除锁定尚未锁定的互斥锁,则会产生不确定的行为。

    条件变量:

    #include <pthread.h>
    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond);
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
    int pthread_cond_destroy(pthread_cond_t *cond);
    /* Conditional variable attribute data structure.  */
    struct pthread_condattr
    {
      /* Combination of values:
         Bit 0  : flag whether coditional variable will be shareable between processes.
         Bit 1-7: clock ID.  */
      int value;
    }; 

    注:pthread_cond_wait会先释放mutex,系统将调用线程挂在信号的等待队列上,在函数返回时会重新执行mutex_lock动作。

    上锁冲突:

    如果是这样的操作顺序:

    设想一种最坏的情况:线程A调用pthread_cond_wait后进入睡眠,线程B发送信号后,系统立即调度线程A执行,线程A会因为不能lock到mutex而立即停止

    为了避免这种上锁冲突,调整线程B的操作如下:

    Posix明确允许调用pthread_cond_signal的线程不必是与之关联的mutex的当前属主。但是,posix也说:如果需要可预见的调度行为,那么pthread_cond_signal的调用线程必须锁住mutex

    进程范围:

    系统范围内的多个进程使用共享内存通信时,也需要同步

    #include <pthread.h>
    
    int pthread_mutexattr_setpthread(const pthread_mutexattr_t *attr, int *valptr);
    int pthread_mutexattr_getpthread(const pthread_mutexattr_t *attr, int value);
    int pthread_condattr_setpthread(const pthread_mutexattr_t *attr, int *valptr);
    int pthread_condattr_getpthread(const pthread_mutexattr_t *attr, int value);

     value的值可以设置成 PTHREAD_PROCESS_PRIVATE 或者 PTHREAD_PROCESS_SHARED   (后者代表进程间共享)

    Attention!!!! 现在问题来了:

    进程间共享一个互斥锁,当某一个进程持有一个互斥锁时意外退出。内核不会自动清理该同步锁... 使用读写锁,Posix信号量也有相同的问题。

    使用System V信号量,应用程序可以设置SEM_UNDO选项来让内核自动清理同步中的信号量

    不过,进程终止时,fcntl记录锁是唯一 一个内核总是会自动清理的同步锁类型。

    p.s.  即使内核自动清理了,但是还是会有临界区的数据一致性问题,比如进程修改数据中途,咔...挂了...  

    进程间同步有这么个问题,那么线程呢?

    一个线程在持有锁期间终止,要么是自己调用了pthread_exit,要么是另一个线程调用了pthread_cancel。主动退出的话,会知道自己还拿着锁的...后一种情况的话,可以安装将在被取消是调用的清理函数。API如下(实际上这是两个宏):

    #include <pthread.h>
    void pthread_cleanup_push(void (*routine)(void *), void *arg);
    void pthread_cleanup_pop(int execute);
  • 相关阅读:
    hdu--4336--概率dp
    hdu--3905--dp
    codeforces--279--
    hdu--5023--线段树
    正则表达式
    vim编辑器使用
    圆头像控件,自动监听点击跳转到Activity
    ImageView切换两种状态下的模式
    string字符串截取
    Class对象获取方法
  • 原文地址:https://www.cnblogs.com/xiaokuang/p/4616986.html
Copyright © 2011-2022 走看看