在 C 语言中使用互斥锁
本文将介绍几种在 C 语言中使用互斥锁的方法。
使用 pthread_mutex_t
类型和 pthread_mutex_lock
函数来守护代码的关键部分
线程共享地址空间,这意味着对全局变量等共享数据的修改必须同步,否则,将出现不正确的程序行为。请注意,下面的代码用 pthread_create
调用创建了 4 个额外的线程,并传递 func3
作为它们执行的起点。func3
在 10000 次迭代 for
循环中逐一修改全局变量 shared
。因此,如果四个线程分别将 shared
的值递增 10000,程序应该输出 40000。
如果执行下面的代码,结果将是某个随机整数,但不是 40000。这种行为一般被归为竞赛条件,意味着给定的线程在访问共享变量时没有相互协商即同步。即,往往当它们执行循环
交错时,对共享变量的访问和存储达到不一致,最后得出错误的和。
多个线程修改内存中同一个对象的代码部分称为关键部分。一般来说,关键部分应该用某种类型的锁来保护,迫使其他线程等到当前线程完成执行,并确保它们都能得到正确的增量值。Mutex 是其中一种锁类型,可以利用它来保护关键部分,就像 func3
中的这个 for
循环一样。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
int shared = 0;
void *func3(void* param)
{
printf("Incrementing the shared variable...\n");
for (int i = 0; i < 10000; ++i) {
shared += 1;
}
return 0;
}
int main()
{
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_create(&threads[i], NULL, func3, NULL);
}
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_join(threads[i], NULL);
}
printf("%d\n", shared);
exit(EXIT_SUCCESS);
}
输出:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384
在这种情况下,我们将利用 POSIX 线程库及其内置的 pthread_mutex_t
类型。pthread_mutex_t
类型变量通常被声明为 static
存储持续时间。互斥锁只能在使用前应该只初始化一次。当互斥锁被声明为 static
时,应该使用 PTHREAD_MUTEX_INITIALIZER
宏来初始化它。当互斥锁被初始化后,线程就可以相应地使用 pthread_mutex_lock
和 pthread_mutex_unlock
函数。pthread_mutex_lock
锁定作为唯一参数传递的 mutex 对象。如果互斥锁已经被锁定,调用线程会被阻塞,直到互斥锁变得可用。应该调用 pthread_mutex_unlock
来解锁互斥锁。如果有线程在同一个互斥锁上等待,则由调度策略决定哪个线程获得对象锁。最后,我们对四个线程中的每一个线程都调用 pthread_join
,并打印出整数-shared
,在这种情况下,它应该有正确的值存储。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *func3(void* param)
{
pthread_mutex_lock(&mutex);
printf("Incrementing the shared variable...\n");
for (int i = 0; i < 10000; ++i) {
shared += 1;
}
pthread_mutex_unlock(&mutex);
return 0;
}
int main()
{
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_create(&threads[i], NULL, func3, NULL);
}
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_join(threads[i], NULL);
}
printf("%d\n", shared);
exit(EXIT_SUCCESS);
}
输出:
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn