对于线程之间数据的同步锁,同样有着属性:
1、mutex锁
int pthread_mutexattr_init(pthread_mutexattr_t *);
int pthread_mutexattr_destroy(pthread_mutexattr_t*);
对锁进行初始化和破坏
锁有两种属性。第一种是进程间的共享。这个不是POSIX属性,然而被Single UNIX Specification所支持。属性有两种值,一个是PTHREAD_PROCESS_PRIVATE,一个是PTHREAD_PROCESS_SHARED。在后一种情况下,线程所锁定的内存可以被多个进程共享同步,然而前者是缺省值,因为前者更容易被实现。
第二种属性是mutex锁的类型,分为四种:
对于RECURSIVE类型的锁,可以被锁定多次,同时,也必须解锁相应的次数。也就是说,引进了“锁定计数”的功能。
要设定锁的这种属性,调用函数:
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict, int*restrict);
int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
注意在后者中mutexattr_t没有restrict限定符。如果加上了restrict限定符,可能不能够满足多线程访问的要求,因为可能有多个指针来处理这个mutexattr对象。
2、读写锁
读写锁只有一种属性,pshared
3、条件变量
条件变量也只有一种pshared属性。
函数的"thread-safe”特性
函数如果能够被多个线程同时调用,就称作“线程安全”的。POSIX 1 下如下函数不是线程安全的(参见APUE 表12.9)。如果要用的话,不妨加上mutex锁来协助。另外,对于一些函数,提供了线程安全的函数作为替代。另外对于文件,有
int ftrylockfile(FILE *);
void flockfile(FILE *);
void funlockfile(FILE *);
提供的锁是recursive的。
之所以不是线程安全的,一个重要的原因是函数内部有自己的静态存储数据。
线程的私有数据
的确,共享数据让大家伤透脑筋,不过有的时候,需要为各个线程准备不同的数据:我们不能让一群线程通过锁互相排队等待数据。
一个简单的想法是,准备一个数组。然而为了保证各个线程的数据都独立,需要为每个线程准备对应元素。而线程的编号未必很小,也不一定连续。一个解决方法是,提供一个key:
int pthread_key_create(pthread_key*, void(*destructor(void*)));
创建一个key,对于所有线程可以共享一个key,但是不同的线程key对应的数据地址是不同的。对于每个线程,初始化的地址都是NULL。另外,每个key都可以附加一个析构函数。析构函数在线程通过pthread_exit()退出时自动执行。
一个线程可以准备多个key。要除掉一个key,可以适用
int pthread_key_delete(pthread_key_t*);
为了防止重复设定key,需要有一个标志位来确定key是否已经建立。然而不能通过线程内部设定标志位的方法来达到这个目的。因为检查位和设定位两个操作不是合并的原子操作。可以采用的方法是用pthread_once
int pthread_once(pthread_once_t*,void (*initfunction) (void));
对每个pthread_once_t要先设定PTHREAD_ONCE_INIT值。多个线程对于同一个pthread_once_t,只会有一个线程执行一次。
要通过key来访问数据,可以调用
void* pthread_getspecific(pthread_key_t);
int pthread_setspecfic(pthread_key_t,const void*);
附注:上述提到的”线程的私有数据“是指,一些线程需要调用一个函数,而这个函数需要为不同的线程提供不同的数据。
1、mutex锁
int pthread_mutexattr_init(pthread_mutexattr_t *);
int pthread_mutexattr_destroy(pthread_mutexattr_t*);
对锁进行初始化和破坏
锁有两种属性。第一种是进程间的共享。这个不是POSIX属性,然而被Single UNIX Specification所支持。属性有两种值,一个是PTHREAD_PROCESS_PRIVATE,一个是PTHREAD_PROCESS_SHARED。在后一种情况下,线程所锁定的内存可以被多个进程共享同步,然而前者是缺省值,因为前者更容易被实现。
第二种属性是mutex锁的类型,分为四种:
Relock without unlock | Unlock when not owned | Unlock when unlocked | |
PTHREAD_MUTEX_NORMAL | deadlocl | undefined | undefined |
PTHREAD_MUTEX_ERRORCHECK | error | error | error |
PTHREAD_MUTEX_RECURSIVE | allowed | error | error |
PTHREAD_MUTEX_DEFAULT | undefined | undefined | undefined |
对于RECURSIVE类型的锁,可以被锁定多次,同时,也必须解锁相应的次数。也就是说,引进了“锁定计数”的功能。
要设定锁的这种属性,调用函数:
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict, int*restrict);
int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
注意在后者中mutexattr_t没有restrict限定符。如果加上了restrict限定符,可能不能够满足多线程访问的要求,因为可能有多个指针来处理这个mutexattr对象。
2、读写锁
读写锁只有一种属性,pshared
3、条件变量
条件变量也只有一种pshared属性。
函数的"thread-safe”特性
函数如果能够被多个线程同时调用,就称作“线程安全”的。POSIX 1 下如下函数不是线程安全的(参见APUE 表12.9)。如果要用的话,不妨加上mutex锁来协助。另外,对于一些函数,提供了线程安全的函数作为替代。另外对于文件,有
int ftrylockfile(FILE *);
void flockfile(FILE *);
void funlockfile(FILE *);
提供的锁是recursive的。
之所以不是线程安全的,一个重要的原因是函数内部有自己的静态存储数据。
线程的私有数据
的确,共享数据让大家伤透脑筋,不过有的时候,需要为各个线程准备不同的数据:我们不能让一群线程通过锁互相排队等待数据。
一个简单的想法是,准备一个数组。然而为了保证各个线程的数据都独立,需要为每个线程准备对应元素。而线程的编号未必很小,也不一定连续。一个解决方法是,提供一个key:
int pthread_key_create(pthread_key*, void(*destructor(void*)));
创建一个key,对于所有线程可以共享一个key,但是不同的线程key对应的数据地址是不同的。对于每个线程,初始化的地址都是NULL。另外,每个key都可以附加一个析构函数。析构函数在线程通过pthread_exit()退出时自动执行。
一个线程可以准备多个key。要除掉一个key,可以适用
int pthread_key_delete(pthread_key_t*);
为了防止重复设定key,需要有一个标志位来确定key是否已经建立。然而不能通过线程内部设定标志位的方法来达到这个目的。因为检查位和设定位两个操作不是合并的原子操作。可以采用的方法是用pthread_once
int pthread_once(pthread_once_t*,void (*initfunction) (void));
对每个pthread_once_t要先设定PTHREAD_ONCE_INIT值。多个线程对于同一个pthread_once_t,只会有一个线程执行一次。
要通过key来访问数据,可以调用
void* pthread_getspecific(pthread_key_t);
int pthread_setspecfic(pthread_key_t,const void*);
附注:上述提到的”线程的私有数据“是指,一些线程需要调用一个函数,而这个函数需要为不同的线程提供不同的数据。