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);

}
线程

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);
}

      运行效果:

[wbyq@wbyq ubuntu]$ ./app 
ABCABCABCABCABCABCABCABCABCABC
所有子线程结束,程序退出!

 

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分