Linux 多线程编程:互斥锁(Mutex)详解

在多线程编程中,当多个线程需要访问共享资源时,如果不加以控制,就会导致数据竞争(Data Race),引发程序行为不可预测。互斥锁(Mutex)是解决此类问题的核心同步机制之一。

1. 核心概念

1.1 临界资源(Critical Resource)

一次只允许一个线程访问的共享资源。例如:全局变量、静态变量、堆内存、文件、硬件设备等。

1.2 临界区(Critical Section)

访问临界资源的那段代码。线程进入临界区前必须获得锁,离开临界区后必须释放锁。

1.3 互斥机制(Mutual Exclusion)

通过互斥锁(Mutex)实现。线程在进入临界区前申请锁(加锁),如果锁已被其他线程持有,则当前线程会被阻塞;访问完临界资源后释放锁(解锁),允许其他线程获取。

2. 互斥锁的初始化与销毁

POSIX 线程库(pthread)提供了互斥锁的操作接口。使用前需包含头文件 <pthread.h>

2.1 动态初始化:pthread_mutex_init

c 复制代码
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

参数说明:

  • mutex:指向要初始化的互斥锁对象。
  • attr:互斥锁属性指针。通常传入 NULL 表示使用缺省属性(快速互斥锁)。

返回值:

  • 成功时返回 0
  • 失败时返回错误码(非零),可通过 strerror(errno) 查看错误信息。

示例:

c 复制代码
pthread_mutex_t mutex;
if (pthread_mutex_init(&mutex, NULL) != 0) {
    perror("pthread_mutex_init failed");
    exit(EXIT_FAILURE);
}

2.2 静态初始化:PTHREAD_MUTEX_INITIALIZER

对于全局或静态的互斥锁,可以使用宏进行静态初始化,无需调用 pthread_mutex_init

c 复制代码
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2.3 销毁互斥锁:pthread_mutex_destroy

c 复制代码
int pthread_mutex_destroy(pthread_mutex_t *mutex);

注意事项:

  • 只能销毁已初始化且未被锁定的互斥锁。
  • 在 Linux 中,互斥锁本身不占用系统资源(如文件描述符),因此 pthread_mutex_destroy 的主要作用是检查锁状态(如果锁处于锁定状态,则返回 EBUSY)并使其不可用。
  • 销毁后的互斥锁不可再使用,除非重新初始化。

3. 互斥锁的基本使用

3.1 加锁:pthread_mutex_lock

c 复制代码
int pthread_mutex_lock(pthread_mutex_t *mutex);
  • 如果互斥锁未被锁定,则调用线程将其锁定并立即返回。
  • 如果互斥锁已被其他线程锁定,则调用线程将被阻塞,直到锁被释放。

3.2 解锁:pthread_mutex_unlock

c 复制代码
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 释放由调用线程锁定的互斥锁。
  • 如果其他线程正在等待该锁,其中一个将被唤醒并获得锁。

3.3 尝试加锁:pthread_mutex_trylock

c 复制代码
int pthread_mutex_trylock(pthread_mutex_t *mutex);
  • 尝试锁定互斥锁。
  • 如果锁可用,则锁定并返回 0
  • 如果锁已被其他线程锁定,则立即返回错误码 EBUSY,而不会阻塞调用线程。

4. 完整使用示例

下面是一个简单的多线程计数器示例,演示如何使用互斥锁保护共享变量。

c 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define THREAD_NUM 5
#define COUNT_LIMIT 10000

int counter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* increment(void* arg) {
    for (int i = 0; i < COUNT_LIMIT; ++i) {
        pthread_mutex_lock(&mutex); // 进入临界区前加锁
        counter++;
        pthread_mutex_unlock(&mutex); // 离开临界区后解锁
    }
    return NULL;
}

int main() {
    pthread_t threads[THREAD_NUM];

    // 创建多个线程同时增加计数器
    for (int i = 0; i < THREAD_NUM; ++i) {
        pthread_create(&threads[i], NULL, increment, NULL);
    }

    // 等待所有线程结束
    for (int i = 0; i < THREAD_NUM; ++i) {
        pthread_join(threads[i], NULL);
    }

    printf("Final counter value: %d (expected: %d)\n", counter, THREAD_NUM * COUNT_LIMIT);
    return 0;
}

输出结果:

复制代码
Final counter value: 50000 (expected: 50000)

如果没有互斥锁保护,多个线程同时执行 counter++(该操作非原子)会导致最终结果小于预期。

相关推荐
Bonnie_12156 分钟前
08-JUC并发基础-AQS-补充共享锁
java·开发语言
qq_401700417 分钟前
Qt 程序启动太乱?重新设计你的 Application 生命周期
开发语言·qt
行者-全栈开发16 分钟前
【Linux内核】CVE-2026-46242:Bad Epoll Linux 内核 epoll UAF 漏洞修复指南(99%可靠root的云安全噩梦)
linux·运维·服务器·cve-2026-46242·linux内核漏洞·use-after-free·云多租户安全
A_cainiao_A17 分钟前
【ggml系列】【第四篇】ggml_graph_compute 多线程计算引擎与算子分发源码深度解析
开发语言·c++·矩阵
信鸽爱好者31 分钟前
一人多台电脑办公模式:windows 电脑A远程桌面操作ubuntu电脑B
linux·运维·ubuntu
小白学大数据39 分钟前
基于Python的抖音网页版视频点赞数增长趋势追踪系统设计与实现
开发语言·爬虫·python·搜索引擎·音视频
木由里予40 分钟前
TEE(Trusted Execution Environment)技术详解
java·linux·开发语言·网络·嵌入式硬件·android-studio
JckOLF04Z1 小时前
C#客户端的异步操作
开发语言·c#
曹牧1 小时前
C#:注释嵌套
开发语言·c#
中国搜索直付通1 小时前
游戏车机端支付通道,会是下一个被低估的合规战场吗?
java·大数据·开发语言·人工智能·游戏