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

}

死锁的避免

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

避免方法:

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

  • 调整锁的顺序

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

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

相关推荐
fpcc11 小时前
C++编程实践——eventFD
linux·c++
虚伪的空想家11 小时前
ip网段扫描机器shell脚本
android·linux·网络协议·tcp/ip·shell·脚本·network
Shingmc311 小时前
【Linux】进程概念(二)
linux
lkbhua莱克瓦2411 小时前
Java练习——正则表达式2
java·开发语言·笔记·正则表达式·github·学习方法
立志成为大牛的小牛11 小时前
数据结构——三十六、拓扑排序(王道408)
数据结构·学习·程序人生·考研·算法
degen_11 小时前
DXE流程
c语言·笔记·bios
2301_7965125211 小时前
Rust编程学习 - 如何快速构建一个单线程 web server
前端·学习·rust
阿巴~阿巴~11 小时前
死锁防范:四大条件与破解之道
linux·服务器·线程·线程安全·死锁
十五学长11 小时前
程序设计C语言
c语言·开发语言·笔记·学习·考研
阿巴~阿巴~17 小时前
Linux同步机制:POSIX 信号量 与 SystemV信号量 的 对比
linux·服务器·线程·信号量·线程同步·posix·system v