zoukankan      html  css  js  c++  java
  • 互斥锁概念简单说明和举例

    本文内容主要来自博文:Linux系统编程——线程同步与互斥:互斥锁

    同时补充以下博文说明:

      [1]  Linux线程-互斥锁pthread_mutex_t

      [2]  POSIX 互斥锁: pthread_mutex_t

     

    为什么需要互斥锁?

    在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的。

    下面我们用程序模拟一下这个过程,线程一需要打印“ hello ”,线程二需要打印“ world ”,不加任何处理的话,打印出来的内容会错乱:

        #include <stdio.h>  
        #include <pthread.h>  
        #include <unistd.h>  
          
        // 打印机  
        void printer(char *str)  
        {  
            while(*str!='')  
            {  
                putchar(*str);    
                fflush(stdout);  
                str++;  
                sleep(1);  
            }  
            printf("
    ");   
        }  
          
        // 线程一  
        void *thread_fun_1(void *arg)  
        {  
            char *str = "hello";  
            printer(str); //打印  
        }  
          
        // 线程二  
        void *thread_fun_2(void *arg)  
        {  
            char *str = "world";  
            printer(str); //打印  
        }  
          
        int main(void)  
        {  
            pthread_t tid1, tid2;  
              
            // 创建 2 个线程  
            pthread_create(&tid1, NULL, thread_fun_1, NULL);  
            pthread_create(&tid2, NULL, thread_fun_2, NULL);  
          
            // 等待线程结束,回收其资源  
            pthread_join(tid1, NULL);  
            pthread_join(tid2, NULL);   
              
            return 0;  
        }  

    实际上,打印机是有做处理的,我在打印着的时候别人是不允许打印的,只有等我打印结束后别人才允许打印。这个过程有点类似于,把打印机放在一个房间里,给这个房间安把锁,这个锁默认是打开的。当 A 需要打印时,他先过来检查这把锁有没有锁着,没有的话就进去,同时上锁在房间里打印。而在这时,刚好 B 也需要打印,B 同样先检查锁,发现锁是锁住的,他就在门外等着。而当 A 打印结束后,他会开锁出来,这时候 B 才进去上锁打印。


    而在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。


    互斥锁的操作流程如下:

    1)在访问共享资源后临界区域前,对互斥锁进行加锁。

    2)在访问完成后释放互斥锁导上的锁。

    3)对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。


    互斥锁的数据类型是: pthread_mutex_t


    互斥锁基本操作


    以下函数需要的头文件:

    #include <pthread.h>


    1)初始化互斥锁

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

    功能:

    初始化一个互斥锁。

    参数:

    mutex:互斥锁地址。类型是 pthread_mutex_t 。
    attr:设置互斥量的属性,通常可采用默认属性,即可将 attr 设为 NULL

    可以使用宏 PTHREAD_MUTEX_INITIALIZER 静态初始化互斥锁,比如:
    pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
    这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_mutex_init() 来完成动态初始化,不同之处在于 PTHREAD_MUTEX_INITIALIZER 宏不进行错误检查。

    返回值:

    成功:0,成功申请的锁默认是打开的。

    失败:非 0 错误码


    2)上锁

    int pthread_mutex_lock(pthread_mutex_t *mutex);

    功能:

    对互斥锁上锁,若互斥锁已经上锁,则调用者一直阻塞,直到互斥锁解锁后再上锁。

    参数:

    mutex:互斥锁地址。

    返回值:

    成功:0

    失败:非 0 错误码


    int pthread_mutex_trylock(pthread_mutex_t *mutex);

    调用该函数时,若互斥锁未加锁,则上锁,返回 0;若互斥锁已加锁,则函数直接返回失败,即 EBUSY。


    3)解锁

    int pthread_mutex_unlock(pthread_mutex_t * mutex);

    功能:

    对指定的互斥锁解锁。

    参数:

    mutex:互斥锁地址。

    返回值:

    成功:0

    失败:非 0 错误码


    4)销毁互斥锁

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    功能:

    销毁指定的一个互斥锁。互斥锁在使用完毕后,必须要对互斥锁进行销毁,以释放资源。

    参数:

    mutex:互斥锁地址。

    返回值:

    成功:0

    失败:非 0 错误码


    互斥锁应用实例

    我们通过互斥锁完善上面的例子,示例代码如下:

        #include <stdio.h>  
        #include <pthread.h>  
        #include <unistd.h>  
          
        pthread_mutex_t mutex; //互斥锁  
          
        // 打印机  
        void printer(char *str)  
        {  
            pthread_mutex_lock(&mutex); //上锁  
            while(*str!='')  
            {  
                putchar(*str);    
                fflush(stdout);  
                str++;  
                sleep(1);  
            }  
            printf("
    ");   
            pthread_mutex_unlock(&mutex); //解锁  
        }  
          
        // 线程一  
        void *thread_fun_1(void *arg)  
        {  
            char *str = "hello";  
            printer(str); //打印  
        }  
          
        // 线程二  
        void *thread_fun_2(void *arg)  
        {  
            char *str = "world";  
            printer(str); //打印  
        }  
          
        int main(void)  
        {  
            pthread_t tid1, tid2;  
              
            pthread_mutex_init(&mutex, NULL); //初始化互斥锁  
              
            // 创建 2 个线程  
            pthread_create(&tid1, NULL, thread_fun_1, NULL);  
            pthread_create(&tid2, NULL, thread_fun_2, NULL);  
          
            // 等待线程结束,回收其资源  
            pthread_join(tid1, NULL);  
            pthread_join(tid2, NULL);   
              
            pthread_mutex_destroy(&mutex); //销毁互斥锁  
              
            return 0;  
        }  
    
  • 相关阅读:
    使用某些 DOCTYPE 时会导致 document.body.scrollTop 失效
    VB.NET 笔记1
    知识管理系统Data Solution研发日记之一 场景设计与需求列出
    知识管理系统Data Solution研发日记之五 网页下载,转换,导入
    折腾了这么多年的.NET开发,也只学会了这么几招 软件开发不是生活的全部,但是好的生活全靠它了
    分享制作精良的知识管理系统 博客园博客备份程序 Site Rebuild
    知识管理系统Data Solution研发日记之四 片段式数据解决方案
    知识管理系统Data Solution研发日记之二 应用程序系列
    知识管理系统Data Solution研发日记之七 源代码与解决方案
    知识管理系统Data Solution研发日记之三 文档解决方案
  • 原文地址:https://www.cnblogs.com/space-place/p/7571654.html
Copyright © 2011-2022 走看看