线程创建
#include <pthread.h>
int pthread_create((pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);
/********************************
参数:
thread线程线程标识符
attr表示线程属性
start_routine线程函数的起始地址
arg传递给start_routine的参数
返回值:
成功返回0,否则返回-1
**********************************/
线程中止
中止方式:1)从启动例程返回;2)被同一进程的其他线程取消;3)线程调用pthread_exit
。
#include <pthread.h>
void pthread_exit(void *rval_ptr);
//进程中的其他线程可以通过pthread_join访问到rval_ptr指针;调用成功返回0,否则返回其他值
int pthread_join(pthread_t thread, void **rval_ptr);
当一个线程通过调用pthread_exit
或者从启动例程返回时,进程中别的线程可以通过pthread_join
获取该线程退出状态(存在rval_ptr中)。
注:默认情况下线程中止状态会保存直到对该线程调用pthread_join
,如果线程已经被分离,则会产生未定义行为,需要调用pthread_detach
分离线程,让操作系统在线程退出时收回它所占资源。
线程同步
当一个线程可以修改的变量,其他线程也可以读取或修改,那就需要对这些线程进行同步,确保访问变量存储内容时不会访问到无效值。
避免死锁
1)如果线程试图对一个互斥量加锁两次,会造成死锁;
2)有两个互斥量,第一个线程占有一个,在获取第二个互斥量时阻塞,而第二个线程占有第二个互斥量,获取第一个线程时阻塞,此使也会产生死锁。
解决方法:可以用pthread_tyrlock
,如果占有了一个互斥量,并且pthread_trylock
成功,那么就继续前进,否则释放第一个互斥量,做好清理工作,再重试。
互斥量(mutex)
在访问共享资源之前对互斥量进行设置(加锁),访问完后释放(解锁)互斥量。对互斥量加锁后,其它想访问互斥量的线程都会被阻塞。
#include <pthread.h>
//成功返回0,否则返回-1
int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
当一个以上的线程需要访问动态分配的对象时,可以在对象中嵌入引用计数(是不是很像shared_ptr
),确保所有使用该对象的线程访问完之前不会释放该对象。
pthread_mutex_timedlock
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *tsptr);
该函数与pthread_mutex_lock
基本等价,指定一个线程愿意等待的绝对时间,超时后不会对互斥量加锁而是返回错误码。所以使用该函数可以避免永久阻塞。
读写锁
读写锁比互斥量具有更高的并行性,有三种状态:读模式加锁、写模式加锁和不加锁状态。
一次只有一个线程可以占用写模式的读写锁,但是可以有多个线程占用读模式的读写锁。
适用于对数据结构读的次数远大于写的情况,所以也叫做共享互斥锁。
#