mutex的四种类型
2015-09-08 11:15
225 查看
在多线程的程序中,多线程间一般使用mutex对临界区进行互斥。但这依赖于各线程的协同约定为进入临界区前都必须加锁,而退出临界区前必须解锁,只要其中的一个线程不遵循这个约定就无法做到互斥一致。比如一个函数:
int func()
{
a++;
retrun a;
}
要对这个函数进行保护,可以这样做:
lock(mutex);
ret = func();
unlock(mutex);
但更好的做法是直接在函数内部进行保护,如下:
int func()
{
int b;
lock(mutex);
a++;
b = a;
unlock(mutex);
return b;
}
这样函数提供了自保护,就保证了只要调用这个接口就肯定是协同一致的。
一般来说,编程时都约定对一个加上的锁必须由加锁线程本身去解锁。但事实测试发现,对普通锁,一个线程可以去解另一个线程的加上的锁。测试代码如下:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
void *ThreadFun(void *ptr)
{
pthread_t tid;
int i = *((int *)ptr);
int ret;
tid = pthread_self();
pthread_detach(tid);
if ((i % 2) == 0)
{
printf("[%u] try to lock mutex!/n", tid);
ret = pthread_mutex_lock(&tMutex);
if (ret == 0)
{
printf("[%u] lock mutex sucess!/n", tid);
}
else
{
printf("[%u] lock mutex failed!/n", tid);
}
}
else
{
printf("[%u] try to unlock mutex!/n", tid);
ret = pthread_mutex_unlock(&tMutex);
if (ret == 0)
{
printf("[%u] unlock mutex sucess!/n", tid);
}
else
{
printf("[%u] unlock mutex failed!/n", tid);
}
}
sleep(10);
printf("[%u] exit!/n", tid);
}
int main(int argc, char *argv[])
{
pthread_t tid;
int ret;
int i;
for (i = 0; i < atoi(argv[1]); i++)
{
ret = pthread_create(&tid, NULL, ThreadFun, &i);
if (ret != 0)
{
strerror(ret);
return 0;
}
sleep(1);
}
while(1);
return 0;
}
编译执行结果如下:
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5165
[root@localhost mutexlock]# [3086166944] try to lock mutex!
[3086166944] lock mutex sucess!
[3075677088] try to unlock mutex!
[3075677088] unlock mutex sucess!
[3065187232] try to lock mutex!
[3065187232] lock mutex sucess!
[3054697376] try to unlock mutex!
[3054697376] unlock mutex sucess!
[3044207520] try to lock mutex!
[3044207520] lock mutex sucess!
[3033717664] try to unlock mutex!
[3033717664] unlock mutex sucess!
[3023227808] try to lock mutex!
[3023227808] lock mutex sucess!
[3012737952] try to unlock mutex!
[3012737952] unlock mutex sucess!
[3002248096] try to lock mutex!
[3002248096] lock mutex sucess!
[2991758240] try to unlock mutex!
[2991758240] unlock mutex sucess!
从上可见,对普通互斥锁,其它线程可以去解另一个线程加上的锁。
如果你想有一种锁强制本线程加上的锁只能由本线程来解的话就可以使用纠错锁,把上面的程序稍微改一下就可以验证纠错锁的特性:
把
pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
改成
pthread_mutex_t tMutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
编译执行结果如下:
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5226
[root@localhost mutexlock]# [3086744480] try to lock mutex!
[3086744480] lock mutex sucess!
[3076254624] try to unlock mutex!
[3076254624] unlock mutex failed!
[3065764768] try to lock mutex!
[3055274912] try to unlock mutex!
[3055274912] unlock mutex failed!
[3044785056] try to lock mutex!
[3034295200] try to unlock mutex!
[3034295200] unlock mutex failed!
[3023805344] try to lock mutex!
[3013315488] try to unlock mutex!
[3013315488] unlock mutex failed!
[3002825632] try to lock mutex!
[2992335776] try to unlock mutex!
[2992335776] unlock mutex failed!
从上可见,对纠错锁,线程不能去解另一个线程加上的锁。
另外还有递归锁跟自适应锁,这四个锁之间的区别如下:
锁类型 初始化方式 加解锁特征 调度特征
普通锁 PTHREAD_MUTEX_INITIALIZER 同一线程可重复加锁,解锁一次释放锁 先等待锁的进程先获得锁
嵌套锁 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 同一线程可重复加锁,解锁同样次数才可释放锁 先等待锁的进程先获得锁
纠错锁 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 同一线程不能重复加锁,加上的锁只能由本线程解锁 先等待锁的进程先获得锁
自适应锁 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP 同一线程可重加锁,解锁一次生效 所有等待锁的线程自由竞争
int func()
{
a++;
retrun a;
}
要对这个函数进行保护,可以这样做:
lock(mutex);
ret = func();
unlock(mutex);
但更好的做法是直接在函数内部进行保护,如下:
int func()
{
int b;
lock(mutex);
a++;
b = a;
unlock(mutex);
return b;
}
这样函数提供了自保护,就保证了只要调用这个接口就肯定是协同一致的。
一般来说,编程时都约定对一个加上的锁必须由加锁线程本身去解锁。但事实测试发现,对普通锁,一个线程可以去解另一个线程的加上的锁。测试代码如下:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
void *ThreadFun(void *ptr)
{
pthread_t tid;
int i = *((int *)ptr);
int ret;
tid = pthread_self();
pthread_detach(tid);
if ((i % 2) == 0)
{
printf("[%u] try to lock mutex!/n", tid);
ret = pthread_mutex_lock(&tMutex);
if (ret == 0)
{
printf("[%u] lock mutex sucess!/n", tid);
}
else
{
printf("[%u] lock mutex failed!/n", tid);
}
}
else
{
printf("[%u] try to unlock mutex!/n", tid);
ret = pthread_mutex_unlock(&tMutex);
if (ret == 0)
{
printf("[%u] unlock mutex sucess!/n", tid);
}
else
{
printf("[%u] unlock mutex failed!/n", tid);
}
}
sleep(10);
printf("[%u] exit!/n", tid);
}
int main(int argc, char *argv[])
{
pthread_t tid;
int ret;
int i;
for (i = 0; i < atoi(argv[1]); i++)
{
ret = pthread_create(&tid, NULL, ThreadFun, &i);
if (ret != 0)
{
strerror(ret);
return 0;
}
sleep(1);
}
while(1);
return 0;
}
编译执行结果如下:
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5165
[root@localhost mutexlock]# [3086166944] try to lock mutex!
[3086166944] lock mutex sucess!
[3075677088] try to unlock mutex!
[3075677088] unlock mutex sucess!
[3065187232] try to lock mutex!
[3065187232] lock mutex sucess!
[3054697376] try to unlock mutex!
[3054697376] unlock mutex sucess!
[3044207520] try to lock mutex!
[3044207520] lock mutex sucess!
[3033717664] try to unlock mutex!
[3033717664] unlock mutex sucess!
[3023227808] try to lock mutex!
[3023227808] lock mutex sucess!
[3012737952] try to unlock mutex!
[3012737952] unlock mutex sucess!
[3002248096] try to lock mutex!
[3002248096] lock mutex sucess!
[2991758240] try to unlock mutex!
[2991758240] unlock mutex sucess!
从上可见,对普通互斥锁,其它线程可以去解另一个线程加上的锁。
如果你想有一种锁强制本线程加上的锁只能由本线程来解的话就可以使用纠错锁,把上面的程序稍微改一下就可以验证纠错锁的特性:
把
pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
改成
pthread_mutex_t tMutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
编译执行结果如下:
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5226
[root@localhost mutexlock]# [3086744480] try to lock mutex!
[3086744480] lock mutex sucess!
[3076254624] try to unlock mutex!
[3076254624] unlock mutex failed!
[3065764768] try to lock mutex!
[3055274912] try to unlock mutex!
[3055274912] unlock mutex failed!
[3044785056] try to lock mutex!
[3034295200] try to unlock mutex!
[3034295200] unlock mutex failed!
[3023805344] try to lock mutex!
[3013315488] try to unlock mutex!
[3013315488] unlock mutex failed!
[3002825632] try to lock mutex!
[2992335776] try to unlock mutex!
[2992335776] unlock mutex failed!
从上可见,对纠错锁,线程不能去解另一个线程加上的锁。
另外还有递归锁跟自适应锁,这四个锁之间的区别如下:
锁类型 初始化方式 加解锁特征 调度特征
普通锁 PTHREAD_MUTEX_INITIALIZER 同一线程可重复加锁,解锁一次释放锁 先等待锁的进程先获得锁
嵌套锁 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 同一线程可重复加锁,解锁同样次数才可释放锁 先等待锁的进程先获得锁
纠错锁 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 同一线程不能重复加锁,加上的锁只能由本线程解锁 先等待锁的进程先获得锁
自适应锁 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP 同一线程可重加锁,解锁一次生效 所有等待锁的线程自由竞争
相关文章推荐
- 动态获取和设置控件宽、高
- eclipse安装Aptana 插件,并设置使之能提示css,js,html,帮助编写代码
- 全志a33加触摸屏
- 本地通知UILocalNotification
- UIViewController中的loadView
- windows下安装redis
- 本地通知UILocalNotification
- xcode查找当前程序的沙盒
- 孔板流量计与均速管流量计的比较
- 面向对象基础
- 微信公众平台申请测试接口URL和TOKEN的配置,怎么在本地让微信能通过80端口访问
- 网站禾 只 分之我见
- 如何在安卓中添加安卓API源代码
- fnt 文件解释
- 截图视频缩略图
- System.out.println与System.err.println的区别(输出顺序!!!)
- js弹出框、对话框、提示框、弹窗汇总
- 中断和异常
- LeetCode ||Insertion Sort List
- myeclipse 10 关于building workspace 的优化