一个正常的多线程程序,为了防止多个线程在差不多一个时间里对一个数据做手脚,在每个线程上都是要上锁的。每个程序都有自己独有的一个小房间,所谓上锁,就是在它运行的时候把自己的门关紧,然后在房间里对数据们做不可描述的事情,其他程序想来对数据做手脚,不可能的,它们只有在外面等着,只有等到我处理完事情后自己把门开开,也就是所谓的解锁。
今天我们来简要分析一下互斥锁的用法,多线程的程序上次已经解释过了,这里不再废话。
函数原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_var = 0;
pthread_mutex_t lock; //生成一把叫lock的锁
void *thread_worker1(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock); //现在开始上锁,处理数据
printf("thread1 g_var=%d\n",++g_var);
pthread_mutex_unlock(&lock); //释放锁,其他程序可以使用数据
sleep(1);
}
return NULL;
}
void *thread_worker2(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock); //同样上锁
printf("thread2 g_var=%d\n",--g_var); //为了观察数据变化,我将它改为-1
pthread_mutex_unlock(&lock); //释放锁
sleep(1);
}
return NULL;
}
int main(int argc,char **argv)
{
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1,NULL,thread_worker1,"haha");
printf("start thread_worker1[%lu]\n",tid1);
pthread_create(&tid2,NULL,thread_worker2,"xixi");
printf("start thread_worker2[%lu]\n",tid2);
while(1)
{
printf("g_var=%d\n",++g_var);
sleep(1);
}
return 0;
}
接下来我们看执行结果,给大家打印长一点。这样,我们可以轻松看到,每两个相邻的数据间只相差1,也就是说一个线程在操作数据的时候,其他线程都在旁观,说明我们上锁是较为成功的。
[lingyun@localhost file]$ ./a.out
start thread_worker1[3078187888]
start thread_worker2[3067698032]
g_var=1
thread2 g_var=0
thread1 g_var=1
g_var=2
thread2 g_var=1
thread1 g_var=2
g_var=3
thread2 g_var=2
thread1 g_var=3
g_var=4
thread2 g_var=3
thread1 g_var=4
g_var=5
thread2 g_var=4
thread1 g_var=5
g_var=6
thread2 g_var=5
thread1 g_var=6
g_var=7
thread2 g_var=6
thread1 g_var=7
g_var=8
thread2 g_var=7
thread1 g_var=8
g_var=9
thread2 g_var=8
thread1 g_var=9
g_var=10
thread2 g_var=9
thread1 g_var=10
最后给大家演示一下死锁,比如同一把锁在一个线程上放两次,在一个线程里敲两遍 pthread_mutex_lock(&lock),程序肯定死掉,这并非真正意义上的死锁。所谓的死锁最重要的一点是你的上锁和解锁的顺序不恰当引起的。比方说一个人要先去完厕所后去书房,而另一个人要先去完书房后去厕所,而前一个人已经进了厕所在等书房开门,而后一个人进了书房在等厕所开门,两个人都在等,无休无止地等,于是便形成了死锁。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_var = 0;
pthread_mutex_t lock;
pthread_mutex_t suo;
void *thread_worker1(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock);
sleep(1); //已获取lock锁,等待线程2获取suo锁
pthread_mutex_lock(&suo);
printf("thread1 g_var=%d\n",++g_var);
pthread_mutex_unlock(&suo);
pthread_mutex_unlock(&lock);
sleep(1);
}
return NULL;
}
void *thread_worker2(void *arg)
{
while(1)
{
pthread_mutex_lock(&suo);
sleep(1); //已获取suo锁,等待线程1获取lock锁
pthread_mutex_lock(&lock);
printf("thread2 g_var=%d\n",--g_var);
pthread_mutex_unlock(&lock);
pthread_mutex_unlock(&suo);
sleep(1);
}
return NULL;
}
int main(int argc,char **argv)
{
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1,NULL,thread_worker1,"haha");
printf("start thread_worker1[%lu]\n",tid1);
pthread_create(&tid2,NULL,thread_worker2,"xixi");
printf("start thread_worker2[%lu]\n",tid2);
while(1)
{
printf("g_var=%d\n",++g_var);
sleep(1);
}
return 0;
}
我们再看它的执行结果,就这样,线程1和线程2互相等待对方开锁,又迟迟不开自己的锁,给双方都造成麻烦,也就都无法顺利执行,剩下的就只有主程序还在孤独地自加。
[lingyun@localhost file]$ gcc lock.c -lpthread
[lingyun@localhost file]$ ./a.out
start thread_worker1[3078122352]
start thread_worker2[3067632496]
g_var=1
g_var=2
g_var=3
g_var=4
g_var=5
g_var=6
g_var=7
g_var=8
g_var=9
g_var=10
这就好比人与人之间,俗话说得好,退一步海阔天空,互相包容体谅,才能更加长远地走下去啊。