Linux互斥量&读写锁

一、互斥量

1.临界资源

同一时刻只允许一个进程/线程访问的共享资源(比如文件、外设打印机)

2.临界区

访问临界资源的代码

3.互斥机制

mutex互斥锁,用来避免临界资源的访问冲突,访问临界资源前申请互斥锁,访问完释放锁

形象点的说法 好比有一个公共卫生间,进去使用的人会给门上锁,使用完会开锁

4.创建互斥锁

cpp 复制代码
/*动态创建*/
pthread_mutex_t mutex
pthread_mutex_t_init(pthread_mutex_t *mutex,互斥锁属性 给NULL默认即可)
/*静态创建*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

5.销毁互斥锁

cpp 复制代码
pthread_mutex_destory(pthread_mutex_t *mutex)

Linux中,互斥锁不占任何资源,所以销毁锁不是必须的,可利用其返回值查询锁状态,锁定时返回EBUSY

6.申请互斥锁(P操作)

cpp 复制代码
pthread_mutex_lock(pthread_mutex_t *mutex) //无锁时阻塞等待
pthread_mutex_trylock(pthread_mutex_t *mutex) //无锁返回EBUSY

7.释放互斥锁(V操作)

cpp 复制代码
pthread_mutex_unlock(pthread_mutex_t *mutex) 
cpp 复制代码
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


FILE *fp;
void *func2(void *arg){
    pthread_detach(pthread_self());
    printf("This func2 thread\n");
    
    char str[]="I write func2 line\n";
    char c;
    int i=0;
    while(1){
        pthread_mutex_lock(&mutex);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_mutex_unlock(&mutex);
        i=0;
        usleep(1);

    }

    pthread_exit("func2 exit");

}

void *func(void *arg){
    pthread_detach(pthread_self());
    printf("This is func1 thread\n");
    char str[]="You read func1 thread\n";
    char c;
    int i=0;
    while(1){
        pthread_mutex_lock(&mutex);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            i++;
            usleep(1);
        }
        pthread_mutex_unlock(&mutex);
        i=0;
        usleep(1);

    }
    pthread_exit("func1 exit");
}


int main(){
    pthread_t tid,tid2;
    void *retv;
    int i;
    fp = fopen("1.txt","a+");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }


    pthread_create(&tid,NULL,func,NULL);
    pthread_create(&tid2,NULL,func2,NULL);
    while(1){    
        sleep(1);
    } 

}

二、读写锁

与互斥锁的区别是:

  • 互斥锁对所有线程一视同仁,同一时刻只允许一个线程访问临界资源

  • 读写锁区分读者和写者同一时刻只允许一个写者 访问临界资源,而读者允许多个同时访问,更具体地:

    • 写锁状态时,其他写锁、读锁都被阻塞;

    • 读锁状态时,读锁不阻塞,写锁阻塞,但在写锁阻塞之后申请的读锁要阻塞等待写锁(否则重要的内容一直写不进去)

cpp 复制代码
pthread_rwlock_t rwlock //定义读写锁
/*申请写锁*/
pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
/*申请读锁*/
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
/*释放锁*/
pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
/*销毁读写锁*/
pthread_rwlock_destory(pthread_rwlock_t *rwlock)
cpp 复制代码
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>


pthread_rwlock_t rwlock;

FILE *fp;
void * read_func(void *arg){
    pthread_detach(pthread_self());
    printf("read thread\n");
    char buf[32]={0};
    while(1){
        //rewind(fp);
        pthread_rwlock_rdlock(&rwlock);
        while(fgets(buf,32,fp)!=NULL){
            printf("%d,rd=%s\n",(int)arg,buf);
            usleep(1000);
        }
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }

}



void *func2(void *arg){
    pthread_detach(pthread_self());
    printf("This func2 thread\n");
    
    char str[]="I write func2 line\n";
    char c;
    int i=0;
    while(1){
        pthread_rwlock_wrlock(&rwlock);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_rwlock_unlock(&rwlock);
        i=0;
        usleep(1);

    }

    pthread_exit("func2 exit");

}

void *func(void *arg){
    pthread_detach(pthread_self());
    printf("This is func1 thread\n");
    char str[]="You read func1 thread\n";
    char c;
    int i=0;
    while(1){
        pthread_rwlock_wrlock(&rwlock);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            i++;
            usleep(1);
        }
        pthread_rwlock_unlock(&rwlock);
        i=0;
        usleep(1);

    }
    pthread_exit("func1 exit");
}


int main(){
    pthread_t tid1,tid2,tid3,tid4;
    void *retv;
    int i;
    fp = fopen("1.txt","a+");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }
    pthread_rwlock_init(&rwlock,NULL);
    pthread_create(&tid1,NULL,read_func,1);
    pthread_create(&tid2,NULL,read_func,2);
    pthread_create(&tid3,NULL,func,NULL);
    pthread_create(&tid4,NULL,func2,NULL);
    while(1){    
        sleep(1);
    } 

}

死锁的避免

概念:有两把锁以上时,多个线程各自申请到锁时,紧接着申请其他线程占用着的锁,它们都会处于阻塞等待,形成【死锁】

避免方法:

  • 锁越少越好,一把锁无需考虑死锁问题

  • 调整锁的顺序

    • 一种笨策略是,某个线程如果想要申请多个锁,那么可以等其释放完,其他线程再申请

    • 另一种笨策略是,各个线程按同样的顺序申请多个锁

相关推荐
hunter2062062 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
不会飞的小龙人2 小时前
Docker Compose创建镜像服务
linux·运维·docker·容器·镜像
不会飞的小龙人2 小时前
Docker基础安装与使用
linux·运维·docker·容器
张3蜂2 小时前
docker Ubuntu实战
数据库·ubuntu·docker
白粥行3 小时前
linux-ubuntu学习笔记碎记
linux·ubuntu
bohu834 小时前
OpenCV笔记3-图像修复
笔记·opencv·图像修复·亮度增强·图片磨皮
jerry-894 小时前
通过配置核查,CentOS操作系统当前无多余的、过期的账户;但CentOS操作系统存在共享账户r***t
linux
大丈夫立于天地间4 小时前
ISIS基础知识
网络·网络协议·学习·智能路由器·信息与通信
doubt。4 小时前
【BUUCTF】[RCTF2015]EasySQL1
网络·数据库·笔记·mysql·安全·web安全
涛ing5 小时前
21. C语言 `typedef`:类型重命名
linux·c语言·开发语言·c++·vscode·算法·visual studio