互斥量属性

	[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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值