当线程并发使用共享变量时,可能会产生不可预期的后果。为此,我们需要使用一定的手段来同步线程对共享变量的访问,互斥锁mutex就是一个解决办法。
下面的代码用于演示,多线程编程下不进行同步可能产生的问题。2个线程并发对全局变量进行递增操作50000次,我们预期该全局变量最终的值为100000,但是不同步的情况下,最终值基本不会是100000.
#include <pthread.h>
#include <stdio.h>
#define NLOOP 50000
int counter = 0;
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
void *doit(void *arg)
{
int i, val, use_mutex = (int)arg;
for(i = 0; i < NLOOP; i++)
{
// 访问counter前进行加锁
// 当其它线程持有该锁的时候, 本线程会阻塞在这里直到锁可用
if(use_mutex)
pthread_mutex_lock(&counter_mutex);
val = counter;
printf("%x: %d\n", pthread_self(), val + 1);
counter = val + 1;
// 访问完毕解锁
if(use_mutex)
pthread_mutex_unlock(&counter_mutex);
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tid1, tid2;
int use_mutex = 0;
// 运行时传递任意一个参数,即表示使用互斥锁进行同步
if(argc == 2)
use_mutex = 1;
// 创建2个线程来并发访问全局变量counter
pthread_create(&tid1, NULL, doit, (void *)use_mutex);
pthread_create(&tid2, NULL, doit, (void *)use_mutex);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
// 待2个线程结束后, 输出最终的counter值
printf("final counter: %d\n", counter);
}
上述代码编译后运行,不加参数的情况下不会使用互斥锁同步,传递任意一个参数即使用互斥锁同步
我们发现,不同步的情况下结果介于[50000,10000]之间,同步的情况下结果为100000
最后,我们测试一下互斥锁带来的开销
不使用互斥锁的情况下,程序的运行时间如下
real 0m1.023s
user 0m0.064s
sys 0m0.304s
使用互斥锁
real 0m1.066s
user 0m0.076s
sys 0m0.280s
发现互斥锁上锁带来的开销并没有太大