本文共 3466 字,大约阅读时间需要 11 分钟。
在并发编程中,互斥是保证多个线程无法同时访问同一资源的关键机制。为了实现互斥,通常会采用互斥锁(Mutual Exclusion Lock, Mutual Lock)。
互斥锁本质上是一个同步机制,它通过确保只有一个线程能够在任何时刻占据整个资源的代码区域(临界区),从而防止资源竞争和数据 races。
在互斥锁的内部,维护了一个计数器(Counter),也称为互斥量(Mutual Exclusion Degree)。这个计数器只有两种可能的值:
当线程试图获取互斥锁时,会检查计数器的值:
获取互斥锁属于原子操作,确保在修改计数器值时不会有其他线程观察到部分更新状态,避免可能的竞态条件。
互斥锁的加锁过程分为三个步骤:
检查寄存器中的值:
交换寄存器与计数器的值:
这一步实际上是一个原子操作,确保在加锁时只允许一个线程成功获取互斥锁。返回加锁结果:
互斥锁的加锁过程必须保证原子性,这意味着在获取互斥锁时,只能有一个线程能够成功加锁,避免数据竞争。
互斥锁的接口定义在 POSIX 标准中,主要包括以下几个函数:
// 静态互斥锁pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 阻塞加锁int pthread_mutex_lock(pthread_mutex_t *mutex);// 非阻塞加锁int pthread_mutex_trylock(pthread_mutex_t *mutex);// 带有超时时间的加锁int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 销毁互斥锁void pthread_mutex_destroy(pthread_mutex_t *mutex);
在多线程应用中,除了互斥锁外,还需要确保某些资源只有在特定条件满足时才能被访问。这个时候,条件变量(Condition Variable)发挥着重要作用。
条件变量通过维护一个等待队列和相关的唤醒操作,实现线程间的协调。即,当某个线程发现在某个条件不满足时(例如资源未准备就绪),它会将自身放入等待队列,等待其他线程的通知。当目标条件满足时,等待队列中的线程会被唤醒,继续执行任务。
条件变量的主要操作包括:
初始化
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
等待接口
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
唤醒接口
int pthread_cond_signal(pthread_cond_t *cond);int pthread_cond_broadcast(pthread_cond_t *cond);
释放条件变量
void pthread_cond_destroy(pthread_cond_t *cond);
以下是一个使用互斥锁和条件变量的典型示例,它模拟了生产者和消费者对资源的互斥访问:
#include#include #include #define THREADCOUNT 2int g_bowl = 0;pthread_mutex_t g_mut;pthread_cond_t g_cond;void* MakeStart(void *arg) { while (1) { pthread_mutex_lock(&g_mut); while (g_bowl > 0) { pthread_cond_wait(&g_cond, &g_mut); } g_bowl++; printf("I am Make %p, g_bowl: %d\n", pthread_self(), g_bowl); pthread_mutex_unlock(&g_mut); pthread_cond_signal(&g_cond); } return NULL;}void* EatStart(void *arg) { while (1) { pthread_mutex_lock(&g_mut); while (g_bowl <= 0) { pthread_cond_wait(&g_cond, &g_mut); } g_bowl--; printf("I am Eat %p, g_bowl: %d\n", pthread_self(), g_bowl); pthread_mutex_unlock(&g_mut); pthread_cond_signal(&g_cond); } return NULL;}int main() { pthread_mutex_init(&g_mut, NULL); pthread_cond_init(&g_cond, NULL); pthread_t prod[THREADCOUNT], cons[THREADCOUNT]; for (int i = 0; i < THREADCOUNT; i++) { if (pthread_create(&prod[i], NULL, MakeStart, NULL) < 0) { perror("prod create error!\n"); return -1; } if (pthread_create(&cons[i], NULL, EatStart, NULL) < 0) { perror("cons create error!\n"); return -1; } } for (int i = 0; i < THREADCOUNT; i++) { pthread_join(prod[i], NULL); pthread_join(cons[i], NULL); } pthread_mutex_destroy(&g_mut); pthread_cond_destroy(&g_cond); return 0;}
互斥锁是实现多线程安全的核心机制,它通过确保唯一的线程能够访问临界资源来避免竞态条件和数据 races。而条件变量则为线程间的协调提供了更高级的控制手段,特别是在资源仅在特定条件下可用时,条件变量能够有效地管理等待队列和唤醒过程。
在实际应用中,互斥锁和条件变量通常结合使用,以实现更复杂的同步需求。通过合理使用这些机制,可以有效地构建高效且安全的多线程应用程序。
转载地址:http://enacz.baihongyu.com/