C语言多线程开发中死锁与读写锁问题详解

 更新时间:2022年05月04日 08:55:48   作者:liufeng2023  
死锁是指多个线程因竞争资源而造成的僵局(互相等待);有些公共数据修改的机会很少,但其读的机会很多。并且在读的过程中会伴随着查找,给这种代码加锁会降低我们的程序效率。读写锁可以解决这个问题;

死锁

有时,一个线程需要同时访问两个或更多不同的共享资源,而每个资源又都由不同的互斥量管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁;

两个或两个以上的进程在执行过程中,因争夺共享资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

死锁的几种场景:

  • 忘记释放锁
  • 重复加锁(重复加相同的锁)
  • 多线程多锁,抢占锁资源

//多线程多锁,抢占锁资源
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 创建2个互斥量
pthread_mutex_t mutex1, mutex2;
void * workA(void * arg) {
    pthread_mutex_lock(&mutex1);
    sleep(1);
    pthread_mutex_lock(&mutex2);
    printf("workA....\n");
    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);
    return NULL;
}
void * workB(void * arg) {
    pthread_mutex_lock(&mutex2);
    sleep(1);
    pthread_mutex_lock(&mutex1);
    printf("workB....\n");
    pthread_mutex_unlock(&mutex1);
    pthread_mutex_unlock(&mutex2);
    return NULL;
}
int main() {
    // 初始化互斥量
    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);
    // 创建2个子线程
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, workA, NULL);
    pthread_create(&tid2, NULL, workB, NULL);
    // 回收子线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    // 释放互斥量资源
    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);
    return 0;
}

执行结果:

读写锁

/*
    读写锁的类型 pthread_rwlock_t
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    案例:8个线程操作同一个全局变量。
    3个线程不定时写这个全局变量,5个线程不定时的读这个全局变量
*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 创建一个共享数据
int num = 1;
// pthread_mutex_t mutex;
pthread_rwlock_t rwlock;
void * writeNum(void * arg) {
    while(1) {
        pthread_rwlock_wrlock(&rwlock);
        num++;
        printf("++write, tid : %ld, num : %d\n", pthread_self(), num);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }
    return NULL;
}
void * readNum(void * arg) {
    while(1) {
        pthread_rwlock_rdlock(&rwlock); 
        printf("===read, tid : %ld, num : %d\n", pthread_self(), num);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }
    return NULL;
}
int main() {
   pthread_rwlock_init(&rwlock, NULL);
    // 创建3个写线程,5个读线程
    pthread_t wtids[3], rtids[5];
    for(int i = 0; i < 3; i++) {
        pthread_create(&wtids[i], NULL, writeNum, NULL);
    }
    for(int i = 0; i < 5; i++) {
        pthread_create(&rtids[i], NULL, readNum, NULL);
    }
    // 设置线程分离
    for(int i = 0; i < 3; i++) {
       pthread_detach(wtids[i]);
    }
    for(int i = 0; i < 5; i++) {
         pthread_detach(rtids[i]);
    }
    pthread_exit(NULL);
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

执行结果:

读时共享,相比互斥锁,提高效率。

到此这篇关于C语言多线程开发中死锁与读写锁问题详解的文章就介绍到这了,更多相关C语言死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++利用两个栈实现队列的方法

    C++利用两个栈实现队列的方法

    这篇文章主要给大家介绍了关于C++利用两个栈实现队列的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C++具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • C/C++调用Fortran的DLL的操作过程

    C/C++调用Fortran的DLL的操作过程

    这篇文章主要介绍了C/C++调用Fortran的DLL,本文以一个简单的加法器为例,通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • C语言新手入门速通手册

    C语言新手入门速通手册

    C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。C 语言是一种广泛使用的计算机语言,它与 Java 编程语言一样普及,二者在现代软件程序员之间都得到广泛使用
    2022-04-04
  • C语言利用sprintf固定字符串输出位数

    C语言利用sprintf固定字符串输出位数

    sprintf 函数是一个 C 语言中的函数,也被许多其他编程语言所支持。这篇文章主要介绍了C语言如何利用sprintf固定字符串输出位数,需要的可以参考一下
    2023-03-03
  • c++实现简单的线程池

    c++实现简单的线程池

    本文介绍的线程池采用C++语言,在windows平台下实现。本着技术分享的精神写作本文同时公布源代码。欢迎大家指出该线程池存在的问题并对当前性能进行讨论。
    2015-03-03
  • C++中的内存对齐实例详解

    C++中的内存对齐实例详解

    这篇文章主要介绍了C++中的内存对齐实例详解的相关资料,这里不仅提供实现方法及代码还提供了手工制作图,来帮助到大家理解这部分知识,需要的朋友可以参考下
    2017-07-07
  • C语言实现猜数字游戏

    C语言实现猜数字游戏

    这篇文章主要为大家详细介绍了C语言实现猜数字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-11-11
  • Linux下C语言的fork()子进程函数用法及相关问题解析

    Linux下C语言的fork()子进程函数用法及相关问题解析

    fork()函数在Linux下可以用于产生一个子进程,这里我们挑选了两个fork相关的面试题,来看一下Linux下C语言的fork()子进程函数用法及相关问题解析
    2016-06-06
  • Qt5代码移植到Qt6的实现

    Qt5代码移植到Qt6的实现

    本文主要介绍了Qt5代码移植到Qt6的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

    C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

    在上一章中我们正式开启了对数据结构中树的讲解,介绍了树的基础。本章我们将学习二叉树的概念,介绍满二叉树和完全二叉树的定义,并对二叉树的基本性质进行一个简单的介绍。本章附带课后练习
    2022-02-02

最新评论