• 多线程互斥锁 pthread_mutex 的使用及初始化问题


    一、互斥锁pthread_mutex的使用

    1、初始化锁

            有两种方法初始化互斥锁,静态方式和动态方式。

    静态方式:

    pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;

    在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量的宏。

    动态方式:

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 

    其中mutexattr用于指定互斥锁属性如下,如果为NULL则使用缺省属性。

            PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。

            PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。 

            PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

            PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

    2、锁的使用

    1. int pthread_mutex_lock(pthread_mutex_t *mutex) //加锁,获取不到锁会挂起
    2. int pthread_mutex_unlock(pthread_mutex_t *mutex) //解锁
    3. int pthread_mutex_trylock(pthread_mutex_t *mutex) //在锁已经被占据时返回EBUSY而不是挂起等待。
    4. int pthread_mutex_destroy(pthread_mutex_t *mutex) //销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。由于在Linux中,互斥锁并不占用任何资源,因此LinuxThreads中的 pthread_mutex_destroy()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。*/

    3、代码示例

    1. #include
    2. #include
    3. #include
    4. void *function(void *arg);
    5. pthread_mutex_t mutex;
    6. int counter = 0;
    7. int main(int argc, char *argv[])
    8. {
    9. int rc1,rc2;
    10. char *str1="wenhaoll";
    11. char *str2="linglong";
    12. pthread_t thread1,thread2;
    13. pthread_mutex_init(&mutex,NULL);
    14. if((rc1 = pthread_create(&thread1,NULL,function,str1)))
    15. {
    16. fprintf(stdout,"thread 1 create failed: %d\n",rc1);
    17. }
    18. if(rc2=pthread_create(&thread2,NULL,function,str2))
    19. {
    20. fprintf(stdout,"thread 2 create failed: %d\n",rc2);
    21. }
    22. pthread_join(thread1,NULL);
    23. pthread_join(thread2,NULL);
    24. return 0;
    25. }
    26. 可以尝试将关于锁的操作去掉,有什么效果
    27. void *function(void *arg)
    28. {
    29. char *m;
    30. m = (char *)arg;
    31. pthread_mutex_lock(&mutex);
    32. while(*m != '\0')
    33. {
    34. printf("%c",*m);
    35. fflush(stdout);
    36. m++;
    37. sleep(1);
    38. }
    39. printf("\n");
    40. pthread_mutex_unlock(&mutex);
    41. }

    二、调试遇到的初始化问题

    问题描述,在锁初始化时,看到很多应用没有初始化,直接使用,如下示例

    1. pthread_mutex_t log_lock;
    2. void write1()
    3. {
    4. char buf[]="111111111111111111111111111111111\n";
    5. int num=0;
    6. while(1)
    7. {
    8. pthread_mutex_lock(&log_lock);
    9. //fwrite(buf,sizeof(buf),1,write_fd);
    10. fprintf(write_fd, buf);
    11. //write(write_fd,buf,strlen(buf));
    12. if(++num>=10000)
    13. {
    14. printf("1 ok\n");
    15. pthread_mutex_unlock(&log_lock);
    16. return;
    17. }
    18. pthread_mutex_unlock(&log_lock);
    19. usleep(10);
    20. }
    21. }
    22. int main()
    23. {
    24. pthread_t write1_id;
    25. //write_fd = open("./testwrite",O_WRONLY | O_APPEND);
    26. write_fd = fopen("./testwrite","a+");
    27. if(write_fd<0)
    28. {
    29. perror("open");
    30. exit(1);
    31. }
    32. //pthread_mutex_init(&log_lock,NULL);
    33. pthread_create(&write1_id,NULL,write1,NULL);
    34. while(1)
    35. {
    36. sleep(1);
    37. }
    38. return 0;
    39. }

    说好的使用前先初始化,但是没有初始化锁也可以正常使用,why?

    于是我尝试用gdb跟了一下,我发现这三种方式

    • pthread_mutex_t log_lock; //直接使用
    • pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
    • pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

    打印出来的pthread_mutex_t结构信息都是一模一样的都是如下:

    1. (gdb) p log_lock
    2. $1 = {__data = {__lock = 0, __count = 0, __owner = 0, __kind = 0, __nusers = 0, {__spins = 0, __list = {__next = 0x0}}}, 
    3.   __size = '\000' 23 times>, __align = 0}

    所以是不是可以说不初始化也可以正常使用锁,如果不初始化使用锁,会有什么样的影响么?

    我们来分析一下为什么会这样,然后给出使用建议。

    pthread_mutex_t log_lock; //直接使用,

        由于是全局变量,编译后结构体成员默认值为0

    pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;

        这个宏实际定义为

        # define PTHREAD_MUTEX_INITIALIZER  { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } 

    pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

        这个初始化函数没有仔细追代码,猜想也是初始化成员为0

    最后建议使用锁时尽量初始化,按照标准流程来。

  • 相关阅读:
    python实现图像添加噪声、噪声处理、滤波器代码实现
    C++基础——前后置++--,流插入提取运算符重载函数
    phpcmsV9.6.0sql注入漏洞分析
    Leetcode 3286. Find a Safe Walk Through a Grid
    Mac/ipad/iphone之间复制粘贴失效的解决办法
    面试常问CAS和ABA问题,你懂了吗?
    Web前端:ReactJS为你的应用程序开发带来的10大好处
    【算法题】 8038. 收集元素的最少操作次数
    java95-线程的优先级
    Java之Gradle【IDEA版】入门到精通(上)(一篇文章精通系列)【安装+基本使用+项目创建+项目部署+文件操作+依赖管理+插件使用】
  • 原文地址:https://blog.csdn.net/u013253075/article/details/126539045