写了段小代码学习互斥锁的作用。
互斥锁的作用:在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
思路是用2个线程对同一个内存位置buffer,进行写和读,为了防止2个线程同时对buffer进行修改,用同一把互斥锁来限制。
写操作简化为把buffer修改为’W’,读简化为把buffer修改为’R’。
在对buffer进行修改之前用pthread_mutex_lock()进行加锁,修改后pthread_mutex_unlock()解锁。
代码如下:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void reader_function(void);
void writer_function(void);
pthread_mutex_t mtx; //声明互斥锁mtx
char buffer;
int main(void)
{
pthread_mutex_init(&mtx, NULL); //用默认属性初始化一个互斥锁对象
pthread_t reader; //创建reader线程
pthread_create(&reader, NULL, (void*) reader_function, NULL);
writer_function();//运行writer
}
void writer_function(void)
{
int i;
for(i=0; i<2; i++)
{
pthread_mutex_lock(&mtx); //对mtx上锁
printf("Writer %d 已经对mtx上锁了. \r\n",i);
buffer = 'W';
printf("Writer %d 把buff修改为%c,\r\n",i, buffer);
printf("Writer %d 解锁mtx. \r\n\n\n", i);
pthread_mutex_unlock(&mtx);//解锁
sleep(1);
}
}
void reader_function(void)
{
int i;
for(i=0; i<2; i++)
{
pthread_mutex_lock(&mtx); //对mtx上锁
printf("Reader %d 已经对mtx上锁了. \r\n",i);
buffer = 'R';
printf("Reader %d 把buff修改为%c,\r\n",i, buffer);
printf("Reader %d 解锁mtx. \r\n\n\n", i);
pthread_mutex_unlock(&mtx);//解锁
sleep(1);
}
}
运行结果为:
进一步测试,把writer 的解锁注释掉,
void writer_function(void)
{
int i;
for(i=0; i<2; i++)
{
pthread_mutex_lock(&mtx); //对mtx上锁
printf("Writer %d 已经对mtx上锁了. \r\n",i);
buffer = 'W';
printf("Writer %d 把buff修改为%c,\r\n",i, buffer);
//printf("Writer %d 解锁mtx. \r\n\n\n", i);
//pthread_mutex_unlock(&mtx);//解锁
sleep(1);
}
}
运行结果如下:
可见,writer 0 修改了buffer后没有解锁mtx,而同线程的writer 1在sleep之后又对mtx加锁,造成死锁,线程一直挂起,reader 也因没办法加锁而一直被挂起。
再上面的基础上把reader 的加锁注释掉:
void reader_function(void)
{
int i;
for(i=0; i<2; i++)
{
//pthread_mutex_lock(&mtx); //对mtx上锁
//printf("Reader %d 已经对mtx上锁了. \r\n",i);
buffer = 'R';
printf("Reader %d 把buff修改为%c,\r\n",i, buffer);
printf("Reader %d 解锁mtx. \r\n\n\n", i);
pthread_mutex_unlock(&mtx);//解锁
sleep(1);
}
}
运行结果如下:
结果说明了writer 线程对mtx的加锁可以在reader 线程里解锁。
再把reader里的解锁注释掉:
void reader_function(void)
{
int i;
for(i=0; i<2; i++)
{
//pthread_mutex_lock(&mtx); //对mtx上锁
//printf("Reader %d 已经对mtx上锁了. \r\n",i);
buffer = 'R';
printf("Reader %d 把buff修改为%c,\r\n",i, buffer);
//printf("Reader %d 解锁mtx. \r\n\n\n", i);
//pthread_mutex_unlock(&mtx);//解锁
sleep(1);
}
}
运行结果如下
reader现在跟互斥锁没关系,在writer死锁一直挂起后,reader不受影响的运行,在这里可以看出多线程程序的优点。
小结:互斥锁可以保证同一资源在同一时间内只能被一个线程使用。
使用完资源后要记得解锁,先后调用2次加锁(中间没有解锁)会导致死锁,线程一直挂起,其他使用此锁的线程也会受到影响。
A线程加的锁能被B线程解锁。
对未加锁的互斥锁进行解锁操作没有意义。