Mutext,pthread_mutext_t
2016-01-10 12:53
375 查看
pthread_mutext_t的用法
基本函数
#include <pthread.h> // 基本操作 int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex);
注意
1. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;这种静态初始化形式是合法的,相当于pthread_mutext_init(&obj, NULL)
2. 重复初始化是错误的,行为未定义
3. 还处于lock状态是不能destroy的,行为未定义
4. destory以后继续使用的行为是未定义的;不过可以再次初始化,然后使用
5. 如果block等待锁期间,收到了信号,那么在执行完信号处理函数以后,会继续block,就像什么也没发生
6. 对一个没初始化的锁执行加锁或解锁,或返回EINVAL
7. pthread_mutex_trylock是非阻塞版本,如果调用pthread_mutext_lock会成功,那么它也会成功,如果调用pthread_mutext_lock会block,那么它会返回EBUSY。
属性设置
// 属性 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_init(pthread_mutexattr_t *attr);
pthread_mutexattr_destroy以后继续使用对象,行为未定义。但可以再次初始化后使用。
pthread_mutexattr_init重复调用,反复初始化,行为未定义。
pthread_mutextattr_t对象用来初始化mutex是拷贝的,一个可以初始化多个。后续修改attr对象不影响已经初始化了的mutex
递归锁
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type); int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
对于递归的支持,依赖于锁的类型。默认值是PTHREAD_MUTEX_DEFAULT。
* PTHREAD_MUTEX_NORMAL:不支持递归,同一个线程在第二次lock的时候,陷入死锁
* PTHREAD_MUTEX_ERRORCHECK:不支持递归,但同一个线程第二次lock的时候,会返回一个错误EDEADLK
* PTHREAD_MUTEX_RECURSIVE:支持递归,维护一个“锁住次数”的变量。.递归加锁次数超系统最大值,返回EAGAIN。不要跟条件变量一起用:It is advised that an application should not use a PTHREAD_MUTEX_RECURSIVE mutex with condition variables because the implicit unlock performed for a pthread_cond_timedwait() or pthread_cond_wait()
may not actually release the mutex (if it had been locked multiple times). If this happens, no other thread can satisfy the condition of the predicate.
* PTHREAD_MUTEX_DEFAULT:不支持递归。同一个线程在第二次lock的时候,行为是未定义的
优先级协议设置
// 优先级相关协议 int pthread_mutexattr_getprotocol(const pthread_mutexattr_t * restrict attr, int *restrict protocol); int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); // 手工设置ceil值 int pthread_mutex_getprioceiling(const pthread_mutex_t *restrict mutex, int *restrict prioceiling); int pthread_mutex_setprioceiling(pthread_mutex_t *restrict mutex, int prioceiling, int *restrict old_ceiling);
PTHREAD_PRIO_NONE
PTHREAD_PRIO_INHERIT
PTHREAD_PRIO_PROTECT。那么线程的优先级应该<=mutex的ceil值。因为ceil值是根据所有用到这个mutex的线程算出来的。如果发现线程的优先级>mutex的ceil,则在lock或者trylock的时候返回EINVAL错误。
程序退出导致死锁
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust); int pthread_mutexattr_getrobust(pthread_mutexattr_t *attr, int *robust);
PTHREAD_MUTEX_STALLED - 解决不了,退出以后其他任务继续block,死锁了。
PTHREAD_MUTEX_ROBUST - 可以解决,退出以后,mutex被解锁,下一个任务会得到锁,然后返回一个错误码为EOWNERDEAD。这时候你需要调用 pthread_mutex_consistent 函数来清除这种状态。然后处理,正常地unlock,后面就跟一般的mutex一样了。如果没有用mutex_consistent,直接unlock,则这个mutex就会永远处于错误状态,任何试图lock的请求都会返回ENOTRECOVERABLE错误。这个情况下就只有destory一条路了。
多进程
// 是否支持多进程访问 int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr, int *restrict pshared); int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
取值可以为:
* PTHREAD_PROCESS_SHARED.支持多进程
* PTHREAD_PROCESS_PRIVATE:默认值。多进程试图lock的行为是未定义的。
*
超时
#include <pthread.h> #include <time.h> int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
超时后返回ETIMEDOUT错误。
所有的函数返回EINTR都是不可能的,肯定是出错了。
处理意外释放
PTHREAD_MUTEX_NORMAL和PTHREAD_MUTEX_DEFAULT:解锁一个别的线程lock住的锁,或者根本没有lock的锁,行为未定义PTHREAD_MUTEX_ERRORCHECK和PTHREAD_MUTEX_RECURSIVE:解锁一个别的线程lock住的锁,或者根本没有lock的锁,返回EPERM
总结
总结一下,要做到dead-lock free,就要做到对递归安全、对退出安全。pthread_mutexattr_t attr; pthread_mutex_t mutex; // 类型看情况选择PTHREAD_MUTEX_RECURSIVE或PTHREAD_MUTEX_ERRORCHECK // 选择PTHREAD_MUTEX_ROBUST;如果编译器不支持,那就在lock的时候用timeout吧 lock的时候要处理的错误: EPERM和EOWNERDEAD
相关文章推荐
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
- mysql 数据库性能追踪与分析
- 树莓派添加DTS功能
- Java Integer和String内存存储
- swift之block的循环引用
- JavaScript 对象 之创建对象 学习笔记
- ionic+phonegap+html+Leancloud实现论坛类跨平台APP
- 判断 n 以内的完全数有多少个!
- 第1章第2节 线性表的链式表示(3)
- RHCE 学习笔记(3)- 文件,目录和帮助
- Spring学习笔记 6. 尚硅谷_佟刚_Spring_Bean 之间的关系
- BAT(批处理)获得参数
- C++ 课本学习笔记(1)
- Linux shell 脚本入门教程+实例
- LeetCode - Minimum Depth of Binary Tree
- 【学习笔记】《STL使用入门教程》第四讲:容器set、函数对象functor与对组pair
- Spring 使用注解方式进行事务管理
- Linux 系统应用编程——多线程经典问题(生产者-消费者)
- Ranorex Vs. Selenium
- Understanding the Bias-Variance Tradeoff