Linux:多线程-互斥锁

1.互斥锁作用

在Linux下,多个线程拥有同一个虚拟地址空间,若多个线程对同一块数据进行操作,可能会产生二义性。造成逻辑混乱。为了保证不发生这些,就需要线程安全。

线程安全的概念:多个线程对同一个临界资源进行争抢访问,但不会造成数据二义性。
线程安全的实现:就要保证同步与互斥。

同步的实现:条件变量/信号量
互斥的实现:互斥锁/信号量

互斥锁为资源引入一个状态信息:锁定/非锁定
当线程要访问一个临界资源的时候,需要先查看这个锁的状态信息

1.若处于开锁(非锁定)状态,就申请到了对临界资源的访问权,并立即更改锁的状态置为锁定状态。
2.若处于锁定状态,则当前线程阻塞,有R(运行)状态变成S(休眠)状态。

2.互斥锁操作

1.定义互斥锁变量
pthread_mutex_t 是一个结构体,锁的类型就是这个。

2.初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
第一个参数传递定义的互斥锁的指针,第二个参数是设置互斥锁的属性
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
这种在定义的时候初始化的方式也可以,POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来初始化锁。

3.上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞接口
int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞接口

4.解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);

5.销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

3.互斥锁原理

在pthread_mutex_t结构体中,有一个变量,当它不为0的时候,线程可以继续执行,否则线程被阻塞。当解锁的时候,会进行唤醒操作,唤醒因为没有获取锁而阻塞的线程。
点这里,这个博客里具体讲了加锁解锁的原理
对锁的状态判断和修改锁的值是一个原子操作,否则可能会导致,一个线程刚判断完可以访问资源进行加锁,另一个线程也正在判断。那这样两个线程可能都会对资源进行访问。
这个原子操作的原理是

1.首先在寄存器里面设置一个变量0。

2.在对锁访问的时候会有一个原子操作,将内存中锁中的值和寄存器中的这个0进行交换。

3.再去判断寄存器中的值,如果是1则可以获取锁,如果是0,就无法获得锁。

在这里插入图片描述

4.互斥锁实例–大妈抢鸡蛋

//通过大妈抢鸡蛋的例子,体会线程安全的重要性以及认识了解互斥锁
//每个线程代表一个大妈。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define MAX_THR 4 //设置创建线程数量
pthread_mutex_t _mutex;//创建互斥锁变量
int egg = 100;//设置100个鸡蛋
void *Dama(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&_mutex);//先上锁,让其他线程阻塞    
        if(egg > 0)                                                 
        {
            printf("%p抢到了第%d个鸡蛋\n",pthread_self(),egg--); 
            //大妈每次抢一个鸡蛋  
        }                                                           
        else                                                           
        {                                                           
            printf("鸡蛋抢完了\n");                                 
            pthread_mutex_unlock(&_mutex);//解锁后退出线程          
            pthread_exit(NULL);                                     
        }                                                           
        pthread_mutex_unlock(&_mutex);//抢到了进行解锁
        usleep(100);
    }
    return NULL;
}
int main()
{
    int i;
    pthread_t tid[MAX_THR];//线程ID

    pthread_mutex_init(&_mutex,NULL);//互斥锁初始化

    for(i = 0;i < MAX_THR; i++)
    {
        int ret = pthread_create(&tid[i],NULL,Dama,NULL);//创建线程
        //参数解释:
        //1.保存当前线程ID
        //2.设置线程属性
        //3.设置线程要去执行的函数地址
        //4.需要给线程函数中传递的参数
        if(ret!=0)//判断线程是否为创建失败
        {
            perror("pthread error\n");
            return -1;
        }
    }
    for(i = 0;i < MAX_THR; i++)
    {
        pthread_join(tid[i],NULL);//线程等待
    }
    pthread_mutex_destroy(&_mutex);//销毁互斥锁
    return 0;
}

发布了35 篇原创文章 · 获赞 13 · 访问量 2113

猜你喜欢

转载自blog.csdn.net/weixin_42458272/article/details/103218486
今日推荐