• Linux下线程间通讯--互斥锁


    Linux下线程间通讯 - - - 互斥锁

    1.互斥锁简介

      在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
      互斥锁(Mutex)是在原子操作API的基础上实现的信号量行为。互斥锁不能进行递归锁定或解锁,能用于交互上下文但是不能用于中断上下文,同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。
      互斥锁是一种简单的加锁的方法来控制对共享资源的存取,当多个线程访问公共资源时,为了保证同一时刻只有一个线程独占资源,就可以通过互斥锁加以限制,在一个时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程才能够对共享资源进行操作。若其他线程希望上锁一个已经上锁了的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。

    2.互斥锁相关函数

      在Posix Thread中定义有一套专门用于线程同步的mutex函数。可以通过静态和动态两种方式创建互斥锁。
      互斥锁有三个类型可供选择:
      PTHREAD_MUTEX_TIMED_NP普通锁(默认锁):
      当一个线程加锁以后,其余请求锁的线程将形成一个阻塞等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
      PTHREAD_MUTEX_RECURSIVE_NP嵌套锁:
      允许同一个线程对同一个锁成功获得多次,并通过多次unlock 解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
      嵌套锁对同一线程可以重复上锁成功,对不同线程不能重复上锁。
      嵌套锁在同一线程中重复上锁,需要重复解锁,否则其它线程将阻塞。
      PTHREAD_MUTEX_ERRORCHECK_NP检错锁:
      如果同一个线程请求同一个锁,则返回 EDEADLK,否则与普通锁类型动作相同。 这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
      检错锁的主要特点就是: 同一个线程无法多次重复进行加锁, 第一次获取锁成功后, 没有解锁的情况下, 如果继续获取锁将不会阻塞, 会返回一个错误值(35)。

    动态方式初始化互斥锁:
    int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);
      attr填NULL表示使用默认属性,创建普通锁。
    //静态方式初始化互斥锁
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    //互斥锁上锁,多次请求则会阻塞
    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);

    3.互斥锁编程

    3.1练习1

      1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。

    #include 
    #include 
    #include 
    /*
    1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。
    */
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁1
    pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁2
    void *pth_work(void *arg)
    {
    	int i,j;
    	for(i=0;i<50;i++)
    	{
    		pthread_mutex_lock(&mutex);
    		printf("-----------子线程第%d遍-----------\n",i);
    		for(j=0;j<10;j++)
    		{
    			printf("hello,world\n");
    		}
    		pthread_mutex_unlock(&mutex2);
    	}
    }
    int main()
    {
    	int i=0,j;
    	pthread_t pthid;
    	pthread_mutex_lock(&mutex2);
    	/*创建子线程*/
    	pthread_create(&pthid,NULL,pth_work,NULL);//创建线程
    	pthread_detach(pthid);
    	for(i=0;i<50;i++)
    	{
    		pthread_mutex_lock(&mutex2);//互斥锁上锁
    		printf("-----------主线程第%d遍-----------\n",i);
    		for(j=0;j<5;j++)//主线程打印
    		{
    			printf("123456\n");
    		}
    		pthread_mutex_unlock(&mutex);
    	}
    	pthread_mutex_destroy(&mutex);
    	pthread_mutex_destroy(&mutex2);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    3.2练习2

      2.创建3线程,线程1打印A,线程2打印B,线程3打印C,按照ABC顺序输出10遍。

    #include 
    #include 
    #include 
    /*
    2.创建3线程,线程1打印A,线程2打印B,线程3打印C,按照ABC顺序输出10遍。
    */
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁1
    pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁2
    pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁3
    void *pth_work(void *arg)
    {
    	int cnt=(int *)arg;
    	//printf("cnt=%d\n",cnt);
    	for(int i=0;i<10;i++)
    	{
    		if(cnt==0)//线程1
    		{
    			pthread_mutex_lock(&mutex);
    			printf("A");
    			pthread_mutex_unlock(&mutex2);
    		}
    		if(cnt==1)//线程2
    		{
    			pthread_mutex_lock(&mutex2);
    			printf("B");
    			pthread_mutex_unlock(&mutex3);
    		}
    		if(cnt==2)//线程3
    		{
    			pthread_mutex_lock(&mutex3);
    			printf("C");
    			fflush(stdout);//刷新缓冲区
    			pthread_mutex_unlock(&mutex);
    		}
    	}
    }
    int main()
    {
    	int i=0;
    	pthread_t pthid[3];
    	pthread_mutex_lock(&mutex2);
    	pthread_mutex_lock(&mutex3);
    	/*创建3个子线程*/
    	for(i=0;i<3;i++)
    	{
    		pthread_create(&pthid[i],NULL,pth_work,(void *)i);
    	}
    	/*等待线程结束*/
    	for(i=0;i<3;i++)
    	{
    		pthread_join(pthid[i],NULL);
    	}
    	printf("\n所有子线程结束,程序退出!\n");
    	pthread_mutex_destroy(&mutex);
    	pthread_mutex_destroy(&mutex2);
    	pthread_mutex_destroy(&mutex3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    运行效果:

    [wbyq@wbyq ubuntu]$ ./app 
    ABCABCABCABCABCABCABCABCABCABC
    所有子线程结束,程序退出!
    
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    基于单片机的显示系统
    javaweb基础:浅聊监听器
    虚拟机构建部署单体项目及前后端分离项目
    直播APP源码搭建:核心的服务器系统
    低代码,没有想象的那么容易,一个过来人的吐槽
    基于自适应Sigmoid型函数的内镜图像增强与空间变颜色再现方法
    HTML5基础
    QT学习管理系统
    JAVA实现数组模拟队列
    【JAVA项目实战】【图书管理系统】用户更新功能【Servlet】+【Ajax】+【Mysql】
  • 原文地址:https://blog.csdn.net/weixin_44453694/article/details/126385556