在多线程编程中,线程同步是确保线程安全访问共享资源的关键,尤其在涉及数据一致性和防止竞态条件时。**互斥锁(Mutex)**是 POSIX 线程编程中实现线程同步的重要机制,能够确保只有一个线程在特定时间内访问共享资源。本文将介绍互斥锁的基本原理、函数用法,并通过示例展示如何在 C 语言中实现多线程同步。
1. 互斥锁的概念
互斥锁(Mutex),顾名思义,是一种“互斥访问”机制。它通过加锁和解锁操作来控制线程对共享资源的访问。加锁后,其他线程必须等待,直到锁被解锁才能访问临界区。这样就保证了多个线程在访问共享资源时的同步性,防止了**竞态条件(race conditions)**的出现。
竞态条件是指程序的执行结果依赖于线程调度的顺序,容易导致不可预测的错误和数据不一致性。互斥锁可以有效地防止这种情况。
2. 互斥锁的主要函数
POSIX 提供了用于管理互斥锁的函数,以下是常用的函数及其说明:
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
: 初始化互斥锁。attr
通常为NULL
,表示使用默认属性。pthread_mutex_lock(pthread_mutex_t *mutex)
: 对互斥锁进行加锁。如果锁已被其他线程持有,调用线程将阻塞,直到锁被释放。pthread_mutex_unlock(pthread_mutex_t *mutex)
: 解锁已持有的互斥锁。只有持有该锁的线程才能解锁。pthread_mutex_destroy(pthread_mutex_t *mutex)
: 销毁互斥锁,释放与该锁相关的资源。
3. 使用互斥锁的多线程编程示例
下面的示例展示了如何在 C 语言中使用 POSIX 线程库(pthread
)和互斥锁来实现线程同步,防止共享资源在多线程环境下的竞态条件。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define NUM_THREADS 3 // 要创建的线程数量int shared_counter = 0; // 共享资源pthread_mutex_t lock; // 定义互斥锁// 线程执行的函数
void* thread_function(void* arg) {// 加锁pthread_mutex_lock(&lock);// 访问共享资源shared_counter++;printf("Thread %ld incremented shared counter to %d\n", (long)arg, shared_counter);// 解锁pthread_mutex_unlock(&lock);pthread_exit(NULL);
}int main() {pthread_t threads[NUM_THREADS];// 初始化互斥锁if (pthread_mutex_init(&lock, NULL) != 0) {perror("Mutex initialization failed");exit(EXIT_FAILURE);}// 创建线程for (long i = 0; i < NUM_THREADS; i++) {if (pthread_create(&threads[i], NULL, thread_function, (void*)i) != 0) {perror("Thread creation failed");exit(EXIT_FAILURE);}}// 等待所有线程完成for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}// 打印最终计数器值printf("Final value of shared counter: %d\n", shared_counter);// 销毁互斥锁pthread_mutex_destroy(&lock);return 0;
}
代码解释
pthread_mutex_t lock
:声明了一个全局互斥锁lock
,用于保护对shared_counter
的访问。pthread_mutex_init(&lock, NULL)
:初始化互斥锁。NULL
表示使用默认的锁属性。- 加锁和解锁:
- 在
thread_function
中,pthread_mutex_lock(&lock)
确保临界区内的代码只能被一个线程访问。 pthread_mutex_unlock(&lock)
释放锁,使其他线程可以进入临界区。
- 在
- 线程创建:使用
pthread_create
创建NUM_THREADS
个线程,每个线程运行thread_function
。 - 线程等待:使用
pthread_join
确保主线程等待所有子线程完成。 pthread_mutex_destroy(&lock)
:销毁互斥锁,释放资源。
输出示例
当程序运行时,输出会类似如下:
Thread 0 incremented shared counter to 1
Thread 1 incremented shared counter to 2
Thread 2 incremented shared counter to 3
Final value of shared counter: 3
由于互斥锁的使用,shared_counter
的值总是以安全的方式被更新,避免了竞态条件的发生。