C语言多线程死锁成因分析与读写锁实战

一颗松果
一颗松果
发布时间:2026-10-16| 5人浏览过
原创

在C语言多线程编程中,资源竞争引发的死锁是常见痛点,而使用读写锁(Read-Write Lock)能有效提升读取密集型场景的性能。本文将解析死锁的典型成因与复现代码,并演示如何通过读写锁实现高效的并发数据访问。

死锁现象与成因分析

当两个或更多线程在等待对方持有的资源时,若无外力干预,系统将陷入永久等待状态,即死锁。在C语言多线程开发中,以下三种情况最容易触发死锁:

  • 忘记释放锁:线程获取互斥量后未执行解锁操作,导致后续线程无法获取资源。
  • 重复加锁:同一线程对非递归互斥量进行二次加锁,会导致自身卡死。
  • 多锁抢占多个线程以不同顺序锁定同一组互斥量,形成环形等待。

以下代码展示了典型的“多线程多锁抢占”场景:线程A先锁mutex1再锁mutex2,而线程B先锁mutex2再锁mutex1。这种逆序加锁极易引发死锁。

// 多线程多锁,抢占锁资源
#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;
}

运行该程序后,由于线程A和线程B互相持有对方需要的锁且不再释放,程序将挂起无法继续执行。

读写锁优化并发效率

为了在保证数据一致性的同时提高读取效率,可以使用读写锁(pthread_rwlock_t)。其核心逻辑为:读时共享,写时独占。即允许同时存在多个读者,但写入者必须独占锁,期间所有读者需等待。

以下案例展示如何使用读写锁让3个写线程和5个读线程并发操作全局变量num:

/*
    读写锁的类型 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);
*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 创建一个共享数据
int num = 1;
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]);
    }
    
    // 主线程等待任意线程退出即可结束,这里直接等待一段时间看效果
    sleep(2);
    pthread_exit(NULL);
    
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

在该场景下,由于读线程之间不会互相阻塞,系统的整体吞吐量将显著高于使用普通互斥锁的情况。

以上就是C语言多线程开发中死锁与读写锁问题的详细内容,更多关于C语言并发编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。