线程同步之互斥锁:pthread_mutex_init,pthread_mutex_lock,pthread_mutex_unlock,pthread_mutex_destroy

主要函数说明

  • int pthread_mutex_init (pthread_mutex_t *__mutex,const pthread_mutexattr_t *__mutexattr)创建一个锁;
  • int pthread_mutex_destroy (pthread_mutex_t *__mutex)销毁锁;
  • int pthread_mutex_trylock (pthread_mutex_t *__mutex)尝试去lock,lock不到时立即返回错误;
  • int pthread_mutex_lock (pthread_mutex_t *__mutex)尝试去lock,lock不到时永久等待;
  • int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, const struct timespec *__restrict __abstime)尝试去lock,lock不到时等待__abstime的时间;
  • int pthread_mutex_unlock (pthread_mutex_t *__mutex)释放一个锁;
  • int pthread_mutexattr_init (pthread_mutexattr_t *__attr)初始化锁参数;
  • int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr)销毁锁参数
  • int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,int __pshared)设定锁的进程共享属性;
  • int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)设定锁的加锁类型;
  • int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr,int __protocol)设定锁对线程优先级的影响策略;

互斥锁使用示例

#include <stdio.h>
#include <string.h>

#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

#define DBG_PRINT(fmt, args...) {printf("%s %d ", __FUNCTION__, __LINE__);printf(fmt,##args);}

/**
 * [msDelay_select 用select()实现的ms级别线程休眠]
 * @param msTime [休眠线程msTime时间,单位毫秒]
 */
void msDelay_select(unsigned msTime)
{
    struct timeval time;
    if(msTime == 0)
    {
        DBG_PRINT("delay time can not be 0!n");
        return;
    }

    if(msTime>=1000)
    {
        time.tv_sec = msTime/1000;
        time.tv_usec = (unsigned long)(msTime%1000)*1000UL;
    }
    else
    {
        time.tv_sec = 0;
        time.tv_usec = (unsigned long)msTime*1000UL;
    }

    select(0, NULL, NULL, NULL, &time);
}

static pthread_mutexattr_t mutexAttr;
static pthread_mutex_t mutexID;
volatile static unsigned count = 0;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static void *_testThread1(void* arg)
{
    while(1)
    {
        /**
         * 永久等待锁mutexID;
         * pthread_mutex_trylock()则是尝试获取锁,如果lock失败立即返回错误;
         * pthread_mutex_timedlock()以设定的最长时间去等待锁,超时直接返回错误;
         */
        pthread_mutex_lock(&mutexID);
        DBG_PRINT("Start:%un", count);
        msDelay_select(200);
        DBG_PRINT("End  :%un", count);
        /**
         * 释放锁;
         */
        pthread_mutex_unlock(&mutexID);
        msDelay_select(10);
    }
}

static void *_testThread2(void* arg)
{
    while(1) 
    {
        pthread_mutex_lock(&mutexID);
        DBG_PRINT("Start:%un", count);
        msDelay_select(100);
        DBG_PRINT("End  :%un", count);
        pthread_mutex_unlock(&mutexID);
        msDelay_select(10);
    }
}

static void _mutexAttr_init_test(void)
{
    /**
     *初始化锁的参数; 
     */
    pthread_mutexattr_init(&mutexAttr);
    //设定为PTHREAD_PROCESS_SHARED则可以进程间共享此mutex;
    //PTHREAD_PROCESS_PRIVATE则只能在创建锁的进程使用;
    pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_PRIVATE);
    /**
     * 设定为PTHREAD_MUTEX_NORMAL,如果重复lock,就会死锁;
     * 设定为PTHREAD_MUTEX_DEFAULT效果同上;
     * 设定为PTHREAD_MUTEX_ERRORCHECK,会检测死锁,如果重复lock,直接返回错误;
     * 设定为PTHREAD_MUTEX_RECURSIVE,可以重复lock,且对同一线程重复的lock,那么必须由该线程做同样次数的unlock,
     * 并且如果尝试unlock其他线程lock的mutex,会直接返回错误,该效果只能使用在PTHREAD_PROCESS_PRIVATE锁的情况;
     */
    pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_NORMAL);
    /**
     * 设定锁是否会影响线程调度的优先级;
     * PTHREAD_PRIO_NONE,锁不影响线程调度优先级;
     * PTHREAD_PRIO_INHERIT,当高优先级线程A需要低优先级线程B lock住的锁时,则B以A的优先级运行;
     * 解锁之后,B线程恢复到自己的优先级运行;
     * PTHREAD_PRIO_PROTECT,拥有锁的线程将以所有等待该锁线程的最高优先级运行;
     * PTHREAD_PRIO_INHERIT和PTHREAD_PRIO_PROTECT只有在线程以RR或者FIFO这两种调度mode下才起作用;
     */
    pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_NONE);
}

/**
 * [mutex_destroy 只运行一次锁销毁]
 */
void mutex_destroy(void)
{
    int ret = 0;
    DBG_PRINT("KOn");
    /**
     * 必须在unlock状态下才能调用pthread_mutex_destroy销毁锁;
     * 不然pthread_mutex_destroy会返回EBUSY;
     */
    pthread_mutex_lock(&mutexID);
    pthread_mutex_unlock(&mutexID);
    ret = pthread_mutex_destroy(&mutexID);
    if(ret != 0)
    {
        DBG_PRINT("The errno is:%sn", strerror(ret));
        return;
    }

    /**
     * 销毁锁创建参数;
     */
    pthread_mutexattr_destroy(&mutexAttr);
}

int main(int argc, const char* argv[])
{
    pthread_t thread1ID, thread2ID;
    int ret = 0;

    _mutexAttr_init_test();
    /**
     * 创建锁,成功返回0;
     */
    if(0!=(ret=pthread_mutex_init(&mutexID, &mutexAttr)))
    {
        DBG_PRINT("create mutex failed! errno:%sn", strerror(ret));
        return -1;
    }

    pthread_create(&thread1ID, NULL, _testThread1, NULL);
    pthread_detach(thread1ID);
    pthread_create(&thread2ID, NULL, _testThread2, NULL);
    pthread_detach(thread2ID);

    while(1)
    {
        count++;
        msDelay_select(300);
        if(count>10)
            pthread_once(&once_control, mutex_destroy);
    }

    return 0;
}

编译运行后,结果如下图:
20180508235419502-1
可以看到当没有运行mutex_destroy()时,_testThread1和_testThread2中的打印都是有序的,并没有出现这两个线程的打印交叉的情况;
当count大于10后,运行mutex_destroy()后销毁了锁,打印如下图:
201805082356296-1
会发现两个线程的打印有出现交叉;

使用互斥锁的一些注意事项

  1. 如果已经创建锁pthread_mutex_t 类型的锁A,然后定义pthread_mutex_t 类型的锁B,不要直接将A赋值给B,然后再使用pthread_mutex_lock(&B)的方式去获取锁,这样是非法的,pthread_mutex_lock会直接返回失败;
  2. 也不要使用memcpy(&B, &A, sizeof(pthread_mutex_t )),然后调用pthread_mutex_lock(&B)的方式去获取锁;这样也没办法成功lock;
  3. 为了安全起见,无论在何种mutex type下,请保证锁的lock与unlock在同一个线程下,一定是成对调用;当然pthread_mutex_trylock和pthread_mutex_timedlock返回失败时,不要调用pthread_mutex_unlock;
  4. 尽量减少锁的粒度;同一把锁,尽量在同一个.c中使用;如果其他地方迫不得已也需要使用该锁(如在嵌入式平台对某些硬件资源访问),也尽量在锁定义处封装一个API extern给其他地方使用;
© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容