[1]使用非默认属性初始化互斥锁时,使用下面两个函数。
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
[2]互斥量的属性
<Linux应用编程>中说明:有多个线程的进程创建子进程会导致非常多问题,所以这里考虑的是两个单进程线程。
1)进程共享属性
1.编译时判断宏_POSIX_THREAD_PROCESS_SHARED符号来判断平台是否支持该属性,
2.运行时将宏_POSIX_THREAD_PROCESS_SHARED传给sysconf函数来检查系统是否支持该属性
3.默认情况下"进程共享属性"为PTHREAD_PROCESS_PRIVATE,表示只有创建同步对象的进程的所有线程才能访问该同步对象。
4.进程1使用共享内存将进程2的内存空间映射到本进程时,如果进程1想使用线程2的互斥量对象。
那么前提条件是:进程2将互斥量对象的属性设置为了_POSIX_THREAD_PROCESS_SHARED,否则不可使用。
5.设置和获取进程共享属性(互斥量)
int pthread_mutexattr_getpshared(const pthreadattr_t attr, int *pshard)
int pthread_mutexattr_setpshared(pthreadattr_t attr, int *pshard)
2)健壮属性
当进程1和进程2通过"共享内存"实现多个进程访问同一个互斥量对象时,需要考虑互斥量的健壮性。
注意:
1.默认情况下,某个进程拿到互斥锁后终止时,其他等待该锁的进程会一种阻塞(死锁)
2.设置了互斥量健壮时,某个进程拿到互斥锁后终止时,会将互斥锁变得不一致(inconsistent)。
1.这时某个进程调用pthread_mutex_lock时会返回WOWNERDEAD(需要恢复的互斥量),这时调用进程并没有获取到互斥锁。
在互斥量被恢复前,一直处于不可用状态。
2.如果不可用状态没被处理,其他进程再次调用pthread_mutex_lock函数,就会返回ENOTRECOVERABLE,导致该互斥量永远不可用。
3.恢复互斥量的接口函数
int pthread_mutex_consistent(pthread_mutexattr_t *mutex)
调用该函数后,互斥量再次变得可用。
3.检测pthread_mutex_lock的返回值 (在进程共享内存同步情况下) 有3种:
0: 不需要恢复的成功
负数: 失败
WOWNERDEAD:(新增)需要恢复的成功(恢复锁的一致性)
4.设置互斥量健壮性的接口
int phtread_mutexattr_getrobust(const pthread_mutexattr_t attr, int *robust)
int phtread_mutexattr_setrobust(pthread_mutexattr_t attr, int *robust)
PTHREAD_MUTEX_STALLED // 非健壮
PTHREAD_MUTEX_ROBUST // 健壮
3)类型属性(控制互斥量的锁定特性)
1.说明
PTHREAD_MUTEX_NORMAL // 不进行任何错误检查与死锁检查
PTHREAD_MUTEX_ERRORCHECK // 提供错误检查
PTHREAD_MUTEX_DEFAULT // 提供默认特性和行为
PTHREAD_MUTEX_RECURSIVE
1.允许同一线程在互斥量解锁之前对互斥量进行多次加锁
2.内部维护了锁的计数,在解锁次数和加锁次数不相同的情况下不会释放锁
2.对比
--------------------------------------------------------------------------------------
互斥量类型 没有解锁时重新加锁 不占用时解锁 在已经解锁时解锁
PTHREAD_MUTEX_NORMAL 死锁 未定义 未定义
PTHREAD_MUTEX_ERRORCHECK 返回错误 返回错误 返回错误
PTHREAD_MUTEX_DEFAULT 未定义 未定义 未定义
PTHREAD_MUTEX_RECURSIVE 允许 返回错误 返回错误
--------------------------------------------------------------------------------------
3.设置/获取互斥量类型的接口
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/acct.h>
#include <errno.h>
#include <sys/times.h>
#include <pthread.h>
#include <signal.h>
/* 测试目的:互斥量属性
--------------------------------------------------------------------------------------
互斥量类型 没有解锁时重新加锁 不占用时解锁 在已经解锁时解锁
PTHREAD_MUTEX_NORMAL 死锁 未定义 未定义
PTHREAD_MUTEX_ERRORCHECK 返回错误 返回错误 返回错误
PTHREAD_MUTEX_DEFAULT 未定义 未定义 未定义
PTHREAD_MUTEX_RECURSIVE 允许 返回错误 返回错误
--------------------------------------------------------------------------------------
PTHREAD_MUTEX_NORMAL // 不进行任何错误检查与死锁检查
PTHREAD_MUTEX_ERRORCHECK // 提供错误检查
PTHREAD_MUTEX_DEFAULT // 提供默认特性和行为
PTHREAD_MUTEX_RECURSIVE
1.允许同一线程在互斥量解锁之前对互斥量进行多次加锁
2.内部维护了锁的计数,在解锁次数和加锁次数不相同的情况下不会释放锁
*/
/* 测试结果
mutextype = PTHREAD_MUTEX_NORMAL
mutextype = PTHREAD_MUTEX_ERRORCHECK
mutextype = PTHREAD_MUTEX_NORMAL
mutextype = PTHREAD_MUTEX_RECURSIVE
mutex_recursive locked1
mutex_recursive locked2
mutex_recursive locked3
mutex_recursive unlocked1
test_mutexattr_normal
test_mutexattr_errorcheck
test_mutexattr_recursive
mutex_recursive unlocked2
mutex_recursive unlocked3
get mutex_recursive
*/
/* 测试结果分析:
PTHREAD_MUTEX_NORMAL:
一致
PTHREAD_MUTEX_ERRORCHECK:
已经加锁时,未解锁再次加锁并没有返回错误,而是阻塞。
PTHREAD_MUTEX_DEFAULT:
设置该类型成功后,互斥锁的属性仍然为PTHREAD_MUTEX_DEFAULT
PTHREAD_MUTEX_RECURSIVE:
一致
*/
// 互斥量
static pthread_mutex_t mutex_normal;
static pthread_mutex_t mutex_errorcheck;
static pthread_mutex_t mutex_defaule;
static pthread_mutex_t mutex_recursive;
// 互斥量属性
static pthread_mutexattr_t mutexattr_normal;
static pthread_mutexattr_t mutexattr_errorcheck;
static pthread_mutexattr_t mutexattr_defaule;
static pthread_mutexattr_t mutexattr_recursive;
static int type_normal, type_errorcheck, typ_defaule, type_recursive;
void printf_mutexattr_type(int type)
{
if(PTHREAD_MUTEX_NORMAL == type)
printf("mutextype = PTHREAD_MUTEX_NORMAL\n");
else if(PTHREAD_MUTEX_ERRORCHECK == type)
printf("mutextype = PTHREAD_MUTEX_ERRORCHECK\n");
else if(PTHREAD_MUTEX_DEFAULT == type)
printf("mutextype = PTHREAD_MUTEX_DEFAULT\n");
else if(PTHREAD_MUTEX_RECURSIVE == type)
printf("mutextype = PTHREAD_MUTEX_RECURSIVE\n");
else
printf("mutexattr_type is undefined\n");
return;
}
// 初始化互斥量属性
void init_allmutexattr()
{
pthread_mutexattr_init(&mutexattr_normal);
pthread_mutexattr_init(&mutexattr_errorcheck);
pthread_mutexattr_init(&mutexattr_defaule);
pthread_mutexattr_init(&mutexattr_recursive);
return;
}
// 设置互斥量的类型
void mutexattr_settype()
{
pthread_mutexattr_settype(&mutexattr_normal, PTHREAD_MUTEX_NORMAL);
pthread_mutexattr_settype(&mutexattr_errorcheck, PTHREAD_MUTEX_ERRORCHECK);
assert(0== pthread_mutexattr_settype(&mutexattr_defaule, PTHREAD_MUTEX_DEFAULT)); // 结果为:PTHREAD_MUTEX_NORMAL
pthread_mutexattr_settype(&mutexattr_recursive, PTHREAD_MUTEX_RECURSIVE);
return;
}
// 获取设置后的属性
void get_mutextype()
{
pthread_mutexattr_gettype(&mutexattr_normal, &type_normal);
pthread_mutexattr_gettype(&mutexattr_errorcheck, &type_errorcheck);
pthread_mutexattr_gettype(&mutexattr_defaule, &typ_defaule);
pthread_mutexattr_gettype(&mutexattr_recursive, &type_recursive);
printf_mutexattr_type(type_normal); // PTHREAD_MUTEX_NORMAL
printf_mutexattr_type(type_errorcheck); // PTHREAD_MUTEX_ERRORCHECK
printf_mutexattr_type(typ_defaule); // PTHREAD_MUTEX_NORMAL
printf_mutexattr_type(type_recursive); // PTHREAD_MUTEX_RECURSIVE
return;
}
// 初始化互斥量
void init_all_mutex()
{
pthread_mutex_init(&mutex_normal, &mutexattr_normal);
pthread_mutex_init(&mutex_errorcheck, &mutexattr_errorcheck);
pthread_mutex_init(&mutex_defaule, &mutexattr_defaule);
pthread_mutex_init(&mutex_recursive, &mutexattr_recursive);
return;
}
void *test_mutexattr_normal(void *arg)
{
printf("test_mutexattr_normal\n");
pthread_mutex_lock(&mutex_normal);
printf("get mutex_normal\n");
return (void *)0;
}
void *test_mutexattr_errorcheck(void *arg)
{
printf("test_mutexattr_errorcheck\n");
if (0 != pthread_mutex_lock(&mutex_errorcheck)) // 已经加锁时,未解锁再次加锁并没有返回错误,而是阻塞。
printf("ERROR: locking mutex_errorcheck\n");
else
printf("get mutex_errorcheck\n");
return (void *)0;
}
/*
void *test_mutexattr_defaule(void *arg)
{
printf("test_mutexattr_defaule\n");
return (void *)0;
}
*/
void *test_mutexattr_recursive(void *arg)
{
printf("test_mutexattr_recursive\n");
pthread_mutex_lock(&mutex_recursive);
printf("get mutex_recursive\n");
return (void *)0;
}
int main(int argc, char **argv)
{
pthread_t tid;
init_allmutexattr();
mutexattr_settype();
get_mutextype();
init_all_mutex();
pthread_mutex_lock(&mutex_normal);
pthread_mutex_lock(&mutex_errorcheck);
// pthread_mutex_lock(&mutex_defaule); // 不能设置该属性
pthread_mutex_lock(&mutex_recursive);
printf("mutex_recursive locked1\n");
pthread_mutex_lock(&mutex_recursive);
printf("mutex_recursive locked2\n");
pthread_mutex_lock(&mutex_recursive);
printf("mutex_recursive locked3\n");
pthread_mutex_unlock(&mutex_recursive);
printf("mutex_recursive unlocked1\n");
// 创建测试线程
pthread_create(&tid, NULL, test_mutexattr_normal,NULL);
pthread_create(&tid, NULL, test_mutexattr_errorcheck,NULL);
//pthread_create(&tid, NULL, test_mutexattr_defaule,NULL); // 无法设置PTHREAD_MUTEX_DEFAULT
pthread_create(&tid, NULL, test_mutexattr_recursive,NULL);
sleep(1);
pthread_mutex_unlock(&mutex_recursive);
printf("mutex_recursive unlocked2\n");
sleep(1);
pthread_mutex_unlock(&mutex_recursive);
printf("mutex_recursive unlocked3\n");
sleep(1);
pause();
return 0;
}