unix中,线程(pthread),互斥锁(mutex),读写锁(rwlock),条件变量(cond)等他们都有一组属性,且功能类似。
他们通用的规则如下:
1.每个对象与其对应的属性对象相关联,通常属性对象对应用程序是不透明的,它提供了一组接口操作属性对象。
2.init函数对属性对象初始化,分配资源
3.destory函数销毁属性对象,回收资源
4.get函数获取属性值
5.set函数设置属性
一:线程属性:
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
detachstate:表示该线程结束后,线程资源会自动被操作系统回收,其他线程不能pthread_join该线程。
int pthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate);
int pthread_attr_setdetachstate(cost pthread_attr_t *attr,int *detachstate);
//detachstate的取值为PTHREAD_CREATE_DETACHED PTHREAD_CREATE_JOINABLE
#include <pthread.h>
int makethread(void *(*fn)(void *), void *arg)
{
int err;
pthread_t tid;
pthread_attr_t attr;
err = pthread_attr_init(&attr);
if (err != 0)
return(err);
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (err == 0)
err = pthread_create(&tid, &attr, fn, arg);
pthread_attr_destroy(&attr);
return(err);
}
线程栈地址属性stackaddr:
int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr, size_t stacksize);
int pthread_attr_getstack(pthread_attr_t *attr,void **stackaddr, size_t *stacksize);
线程栈大小属性stacksize:
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
线程栈之后避免栈溢出的警戒缓冲区大小属性guardsize:
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
二:互斥锁(mutex)属性
1.初始化和销毁
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
PTHREAD_MUTEX_INITIALIZER//对于静态属性类型的初始化
2.获取/设置进程共享属性:可设置的值PTHREAD_PROCESS_PRIVATE/PTHREAD_PROCESS_SHARED
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);
3.获取/设置拥有锁的线程退出后,是否被通知的属性:可设置的值
PTHREAD_MUTEX_STALLED:拥有锁的线程退出后,若未解锁,则继续拥有,其他线程加锁操作会被阻塞,可能导致死锁
PTHREAD_MUTEX_ROBUST:拥有锁的线程退出后,若未解锁,则继续拥有,其他加锁操作阻塞的线程会被通知,出错返回,返回值为EOWNERDEAD,其他线程如果想继续使用该互斥锁,则必须先调用pthread_mutex_consistent,然后调用 pthread_mutex_unlock.然后该锁就可以被继续使用,对lock操作返回值为EOWNERDEAD的锁,如果没有调用pthread_mutex_consistent,那么对该锁唯一合法的操作是使用destroy。
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, int *robust);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,int robust);
int pthread_mutex_consistent(pthread_mutex_t *mutex);
4.获取/设置互斥锁类型属性:PTHREAD_MUTEX_NORMAL(标准互斥锁)/PTHREAD_MUTEX_ERRORCHECK(提供错误检查)
PTHREAD_MUTEX_RECURSIVE(递归互斥锁,可加锁多次)/PTHREAD_MUTEX_DEFAULT(默认锁)
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int type);
三:读写锁(rwlock)属性
1.初始化和销毁
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
PTHREAD_RWLOCK_INITIALIZER//对于静态属性类型的初始化
2.获取/设置进程共享属性:可设置的值PTHREAD_PROCESS_PRIVATE/PTHREAD_PROCESS_SHARED
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,int pshared);
四:条件变量属性
1.初始化和销毁
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
PTHREAD_COND_INITIALIZER//对于静态属性类型的初始化
2.获取/设置进程共享属性:可设置的值PTHREAD_PROCESS_PRIVATE/PTHREAD_PROCESS_SHARED
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr,int pshared);
五:屏障属性
1.初始化和销毁
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
int pthread_barrierattr_init(pthread_barrierattr_t *attr);
2.获取/设置进程共享属性:可设置的值PTHREAD_PROCESS_PRIVATE/PTHREAD_PROCESS_SHARED
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,int pshared);
以下代码段给出初始化一个互斥锁,以便他能在进程间共享属性的过程:
pthread_mutex_t *pmutex;
pthread_mutexattr_t mutexattr;
pmutex=/*some value that points to shared memory,使互斥锁指针指向共享内存区*/
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_setpshared(&mutexattr,PTHREAD_PROCESS_SHARED);
pthread_mutex_init(pmutex,&mutexattr);
pthread_mutexattr_destory(&mutexattr);
下面是一个简单的demo
/*
互斥量 实现 多进程 之间的同步
*/
#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
struct mt
{
int num;
pthread_mutex_t mutex;
pthread_mutexattr_t mutexattr;
};
int main(void)
{
int i;
struct mt* mm;
pid_t pid;
/*
// 创建映射区文件
int fd = open("mt_test",O_CREAT|O_RDWR,0777);
if( fd == -1 )
{
perror("open file:");
exit(1);
}
ftruncate(fd,sizeof(*mm));
mm = mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
unlink("mt_test");
*/
// 建立映射区
mm = mmap(NULL,sizeof(*mm),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
// printf("-------before memset------\n");
memset(mm,0x00,sizeof(*mm));
// printf("-------after memset------\n");
pthread_mutexattr_init(&mm->mutexattr); // 初始化 mutex 属性
pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED); // 修改属性为进程间共享
pthread_mutex_init(&mm->mutex,&mm->mutexattr); // 初始化一把 mutex 锁
pid = fork();
if( pid == 0 ) // 子进程
{
for( i=0; i<10;i++ )
{
pthread_mutex_lock(&mm->mutex);
(mm->num)++;
printf("-child--------------num++ %d\n",mm->num);
pthread_mutex_unlock(&mm->mutex);
sleep(1);
}
}
else
{
for( i=0;i<10;i++)
{
sleep(1);
pthread_mutex_lock(&mm->mutex);
mm->num += 2;
printf("--------parent------num+=2 %d\n",mm->num);
pthread_mutex_unlock(&mm->mutex);
}
wait(NULL);
}
pthread_mutexattr_destroy(&mm->mutexattr); // 销毁 mutex 属性对象
pthread_mutex_destroy(&mm->mutex); // 销毁 mutex 锁
return 0;
}
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
要理解这个函数请看下图,该函数是将fd指定的文件映射到addr为起始地址的共享内存中,offset为文件偏移量,length为映射长度,通常我们指定addr为NULL,它表示内核会为我们分配内存,我们不必关心内存具体的起始地址,返回值指向这个起始地址。该函数的fd=-1,表示分配一块匿名的共享内存区,互斥锁必须存储在共享内存区中才能应用于进程间的同步。