Linux_6 任务之间同步-互斥锁(线程)

1.基本概念

(1)互斥锁的概念

互斥锁:对共享数据进行锁定,保证同一时刻只能有一个线程去操作。

       抢到锁的线程先执行,没有抢到锁的线程需要等待,等锁用完后需要释放,然后其它等待的线程再去抢这个锁,那个线程抢到那个线程再执行。 具体那个线程抢到这个锁我们决定不了,是由cpu调度决定的,但是可以通过延时来控制谁先进行。

(2)互斥锁为资源引入一个状态:锁定/非锁定

       某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

(3)使用互斥锁的目的

  能够保证多个线程访问共享数据不会出现资源竞争及数据错误

互斥锁是通过锁的机制来实现线程间的同步问题。互斥锁的基本流程为:

  • 初始化一个互斥锁:pthread_mutex_init()函数
  • 加锁:pthread_mutex_lock()函数或者pthread_mutex_trylock()函数
  • 对共享资源的操作
  • 解锁:pthread_mutex_unlock()函数
  • 注销互斥锁:pthread_mutex_destory()函数

其中,在加锁过程中,pthread_mutex_lock()函数和pthread_mutex_trylock()函数的过程略有不同:

  • 当使用pthread_mutex_lock()函数进行加锁时,若此时已经被锁,则尝试加锁的线程会被阻塞,直到互斥锁被其他线程释放,当pthread_mutex_lock()函数有返回值时,说明加锁成功;
  • 而使用pthread_mutex_trylock()函数进行加锁时,若此时已经被锁,则会返回EBUSY的错误码。

同时,解锁的过程中,也需要满足两个条件:

  • 解锁前,互斥锁必须处于锁定状态;
  • 必须由加锁的线程进行解锁。

当互斥锁使用完成后,必须进行清除。

 

2.例子

pthread_mutex.c

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>

// 两个线程函数声明
void *thread1_function(void *arg);  
void *thread2_function(void *arg);

int count = 0;
pthread_mutex_t mutex;   // 互斥锁

int main(void)
{
       pthread_t pthread1, pthread2;
       int ret;
 
       pthread_mutex_init(&mutex, NULL);   // 互斥锁初始化,第二个参数可以空指针

       ret = pthread_create(&pthread1, NULL, thread1_function, NULL);
       if(ret != 0)
       {
              perror("pthread_create");
              exit(1);
       }
       
       ret = pthread_create(&pthread2, NULL, thread2_function, NULL);      
       if(ret != 0)
       {
              perror("pthread_craet");
              exit(1);   
       }
       pthread_join(pthread1, NULL);    //监测线程1结束
       pthread_join(pthread2, NULL);    //监测线程2结束
       printf("the thred is over ,process is over too.\n");
       return 0;
}
 

//线程1     线程所有资源依赖于进程,进程结束线程也会结束
void *thread1_function(void *arg)        // arg参数(指针类型)
{
     int i = 1;
     while(1)
     {
          pthread_mutex_lock(&mutex);    // 互斥锁上锁
          for(i = 0; i < 10; i++)        // 上锁状态
          {
              printf("hello world\n");
              sleep(1);                  // 1秒间隔
          }
          pthread_mutex_unlock(&mutex);  // 互斥锁解锁
          sleep(1);
     }
     return NULL; 
}
//线程2
void *thread2_function(void *arg)
{
     int i;
     sleep(1);       // 一秒后上锁
     while(1)
     {
          pthread_mutex_lock(&mutex);    // 互斥锁上锁
          for(i = 0; i < 10; i++)        // 上锁状态
          {
              printf("good morning\n");
              sleep(1);                  // 1秒间隔
          }
          pthread_mutex_unlock(&mutex);  // 互斥锁解锁
          sleep(1);
     }
     return NULL;
}

编译:gcc   pthread_mutex.c   -pthrea

结果: 一个线程运行时另一个无法运行,一直循环

加锁后的火车售票系统 ---避免出现负数票

#include <stdio.h>
#include <pthread.h>
int cnt = 121;
pthread_mutex_t lock;       // 互斥锁
void* pthread1(void* args)  // 线程1
{
	while(1)
	{
		pthread_mutex_lock(&lock); //因为要访问全局的共享变量,所以就要加锁
		if(cnt > 0) //如果有票
		{
			printf("窗口A开始售票,车票是:%d\n",cnt);
			sleep(2);
			cnt--;
			printf("窗口A售票结束,最后一张车票是:%d\n",cnt);
		}
		else
		{
			pthread_mutex_unlock(&lock);
			pthread_exit(NULL);
		}
		pthread_mutex_unlock(&lock);
		sleep(1); //要放到锁的外面,让另一个有时间锁
	}
}
void* pthread2(void* args) // 线程2
{
	while(1)
	{
		pthread_mutex_lock(&lock);  // 上锁
		if(cnt>0)
		{
			printf("窗口B开始售票--车票是:%d\n",cnt);
			sleep(2);
			cnt--;
			printf("窗口B售票结束,最后一张车票是:%d\n",cnt);
		}
		else
		{
			pthread_mutex_unlock(&lock);  // 解锁
			pthread_exit(NULL);
		}
		pthread_mutex_unlock(&lock);      // 解锁
		sleep(1);
	}
}
int main()
{
	pthread_t pthid1 = 0;
	pthread_t pthid2 = 0;
    //初始化锁
	pthread_mutex_init(&lock,NULL); 
    //创建线程
	pthread_create(&pthid1,NULL,pthread1,NULL);
	pthread_create(&pthid2,NULL,pthread2,NULL);
     //等待线程结束
	pthread_join(pthid1,NULL);
	pthread_join(pthid2,NULL);
     //销毁锁
	pthread_mutex_destroy(&lock);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44177768/article/details/127877645