• 线程同步API及它们的属性


    头文件:<pthread.h> 编译记得加 -lpthread库

    1:互斥锁(mutex)

    1.1:互斥锁API

    数据类型:pthread_mutex_t

    // 初始化一个互斥锁
    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    or pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 互斥锁的默认属性

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 等价于 pthread_mutex_init(&mutex, NULL)
    -------------------------------------------------------------------------------------
    // 销毁一个互斥锁
    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_timedlock(pthread_mutex_t *mutex, const struct timespec *time);
    -------------------------------------------------------------------------------------
    // 释放一个互斥锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
                                    以上函数返回值:成功0,失败设置errno

    1.2:互斥锁的属性

    数据类型:pthread_mutexattr_t  

    1.2.0 互斥锁属性之初始化

    // 初始化一个互斥锁属性
    int pthread_mutexattr_init(pthread_mutexattr_t *attr);
    -------------------------------------------------------------------------------------
    // 销毁一个互斥锁属性
    int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
    -------------------------------------------------------------------------------------

    1.2.1 互斥锁属性之pshared 属性

    // 设置pshared属性
    int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
    pshared取值:
    1:PTHREAD_PROCESS_SHAREAD --> 表示此属性的互斥锁放在共享内存中,可以被多个进程中的线程共享
    2:PTHREAD_PROCESS_PRIVATE --> 表示此属性的互斥锁只能被和创建此锁的线程在同一进程中的其他线程共享(推荐默认值)
    // 获取pshared属性
    int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared);

    1.2.2 互斥锁属性之robust属性

    // 设置robust属性(此属性主要使用在锁位于进程间使用的情况)
    /*
    robust的取值:
        1:PTHREAD_MUTEX_STALLED --> 当一个进程在拥有锁的时候异常挂掉,这时另一个进程企图获得锁将一直阻塞,出现
    死锁(deadlock)的情况.
        2:PTHREAD_MUTEX_ROBUST  --> 这时企图获得锁的进程pthread_mutex_lock将返回EOWNERDEAD而不是0,它提示占用
    此锁的进程已经挂掉,需要恢复锁,所以如果使用了mutex的robust属性且设置为PTHREAD_MUTEX_ROBUST,在获得锁时要处理pthread_mutex_lock返回的
    三种情况(不是PTHREAD_MUTEX_ROBUST属性只需处理两种,0成功,其它失败),三种情况是:
        A:调用成功,锁不用恢复(返回0)
        B:调用成功,锁需要恢复(返回EOWNERDEAD)
        C:调用失败(返回其它)
        对于返回情况B,首先应该调用pthread_mutex_consistent函数先恢复锁,再解锁,最后获得锁执行随后的代码.如果未调用pthread_mutex_consistent函数恢复过锁,
    而在B情况后直接解锁,之后获得锁,那么pthread_mutex_lock将返回ENOTRECOVERABLE,提示此锁已经不能再继续使用,这时就只能pthread_mutex_destroy锁之后重新初始
    化锁再使用. 注:互斥锁的robust属性一定程度上提供了死锁的一种解决方案.
    */ int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust); // 获得robust属性 int pthread_mutexattr_getrobust(pthread_mutexattr_t *attr, int *robust); // 恢复锁的状态 int pthread_mutex_consistent(pthread_mutex_t *mutex);

    1.2.3 互斥锁属性之type属性

    // 设置type属性
    /*
    type的四种取值:
        1:PTHREAD_MUTEX_NORMAL     --> 属性默认值
        2:PTHREAD_MUTEX_ERRORCHECK --> 执行锁的错误检查,如死锁,不占用时解锁,已解锁时解锁都会返回错误值提示
        3:PTHREAD_MUTEX_RECURSIVE  --> 允许你在同一线程下连续加锁而不造成死锁(强调是同一线程下),你必须有同次
        数的解锁之后才能释放此锁,条件变量中的互斥锁不要使用此属性,会造成条件的不一致.
        4:PTHREAD_MUTEX_DEFAULT    --> ?
    */
    int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
    // 获得type属性
    int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type);

    -------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------

    2:读写锁(rwlock)

    2.1:读写锁API

    数据类型:pthread_rwlock_t

    // 初始化读写锁
    int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
    or pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;// 读写锁的默认属性

      pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER 等价于 pthread_rwlock_init(&rwlock, NULL)

    -------------------------------------------------------------------------------------
    // 销毁读写锁
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    -------------------------------------------------------------------------------------
    // 读方式获取锁
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    // 非阻塞读方式获取锁
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    // 带有超时的读方式获取锁
    int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *time);
    -------------------------------------------------------------------------------------
    // 写方式获取锁
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    // 非阻塞写方式获取锁
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    // 带有超时的写方式获取锁
    int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *time);
    -------------------------------------------------------------------------------------
    // 解锁
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
                       以上函数返回值:成功0,失败设置errno

    注:读写锁适合使用在临界资源读频率远高于写频率的情况下。

      当临界资源位于读锁定情况下,读方式获取锁会成功,写方式获取锁会被阻塞(如有一个线程以写方式获取锁时被阻塞,内核通常会阻塞之后的以读方式获取锁的进程,防止临界资源一直被读锁定占用)

         当临界资源位于写锁定情况下,读或写方式获取锁都是被阻塞

    2.2:读写锁的属性

    数据类型:pthread_rwlockattr_t 

    2.2.0:读写锁属性之初始化

    // 初始化读写锁属性
    int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
    // 销毁读写锁属性
    int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

    2.2.1:读写锁属性之pshared属性<读写锁只有pshared属性可设置>

    // 设置pshared属性
    int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
    pshared取值:
    1:PTHREAD_PROCESS_SHAREAD --> 表示此属性的读写锁放在共享内存中,可以被多个进程中的线程共享
    2:PTHREAD_PROCESS_PRIVATE --> 表示此属性的读写锁只能被和创建此锁的线程在同一进程中的其他线程共享(推荐默认值)
    // 获取pshared属性
    int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared);

    -------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------

    3:条件变量

    3.1:条件变量API

    数据类型:pthread_cond_t

    // 初始化条件变量
    int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
    -------------------------------------------------------------------------------------
    // 销毁条件变量
    int pthread_cond_destory(pthread_cond_t *cond);
    -------------------------------------------------------------------------------------
    // 等待条件变量为真
    int pthread_cond_wait(pthread_cond_t *cond, pthrad_mutex_t *mutex);
        这个函数会阻塞进程,直到接收到pthread_cond_signal或者pthread_cond_broadcast函数的信号,传递给函数的mutex是一个已被锁住的mutex.
        函数有两个原子操作:
                          1:unlock mutex(解锁的目的是使其它线程有机会获得锁来改变'条件'),阻塞等待获得信号
                          2:获得信号后lock mutex,函数返回
    -------------------------------------------------------------------------------------
    // 带超时的wait
    int pthread_cond_wait(pthread_cond_t *cond, pthrad_mutex_t *mutex);
        超时是指一个绝对值,即目前时间+超时时间
    例:
        void maketimeout(struct timespec *tsp, long minutes)
        {
            struct timeval now;
            gettimeofday(&now, NULL);
            tsp->tv_sec = now.tv_sec;
            tsp->tv_nsec = now.tv_usec * 1000;// 1微妙 = 1000纳秒
            tsp->tv_sec += minutes * 60;
        }

    struct timeval {     struct timespec{
       time_t tv_sec; //秒           time_t tv_sec; //秒
         long tv_usec;//微妙          long tv_nsec; //纳秒
      };                      };   
    ------------------------------------------------------------------------------------- // 通知某一个线程条件满足 int pthread_cond_signal(pthread_cond_t *cond); // 通知所有等待线程条件满足(惊群) int pthread_cond_broadcast(pthread_cond_t *cond);                       以上函数返回值:成功0,失败设置errno

    3.2:条件变量的属性

    数据类型:pthread_condattr_t

    3.2.0:条件变量属性之初始化

    // 初始化条件变量属性
    int pthread_condattr_init(pthread_condattr_t *attr);
    // 销毁条件变量属性
    int pthread_condattr_destroy(pthread_condattr_t *attr);

    3.2.1:条件变量属性之pshared

    // 设置pshared属性
    int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
    pshared取值:
    1:PTHREAD_PROCESS_SHAREAD --> 表示此属性的条件变量放在共享内存中,可以被多个进程中的线程共享
    2:PTHREAD_PROCESS_PRIVATE --> 表示此属性的条件变量只能被和创建此锁的线程在同一进程中的其他线程共享(推荐默认值)
    // 获取pshared属性
    int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared);

    -------------------------------------------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------------------------------------------

    4:自旋锁

    数据类型:pthread_spinlock_t

    操作API:

    // 初始化自旋锁
    int pthread_spin_init(pthread_spinlock_t *spin, int pshared);
        自旋锁的属性只有一个值,即pshared,它有两种取值:
    1:PTHREAD_PROCESS_SHAREAD --> 表示此属性的自旋锁放在共享内存中,可以被多个进程中的线程共享
       2:
    PTHREAD_PROCESS_PRIVATE --> 表示此属性的自旋锁只能被和创建此锁的线程在同一进程中的其他线程共享(此属性的默认值)
    -------------------------------------------------------------------------------------
    // 销毁自旋锁
    int pthread_spinlock_destory(pthread_spinlock_t *spin);
    -------------------------------------------------------------------------------------
    // 获得自旋锁
    int pthread_spinlock_lock(pthread_spinlock_t *spin);
    -------------------------------------------------------------------------------------
    // 非自旋获得自旋锁
    int pthread_spinlock_trylock(pthread_spinlock_t *spin);
    -------------------------------------------------------------------------------------
    // 释放自旋锁
    int pthread_spinlock_unlock(pthread_spinlock_t *spin);
                      以上函数返回值:成功0,失败设置errno

    注:自旋锁和互斥锁类似,唯一的区别就是它是忙等阻塞状态,而互斥锁是通过休眠阻塞,所以自旋锁在等待锁的过程中会消耗大部分CPU时间片,但是可以减少内核的线程间切换作业

  • 相关阅读:
    Linux libcurl使用 (收藏)
    公钥和私钥与认证和签名
    fedora下配置ipv6 dns服务器
    SHA1
    linux IP 命令
    SSL/TLS协议簇加解密流程
    MD5算法实现原理
    container_of深入理解
    diff和patch使用指南
    oracle 笔记
  • 原文地址:https://www.cnblogs.com/Flychown/p/7401819.html
Copyright © 2020-2023  润新知