1. 创建线程
#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数
thread
属于结果参数,函数结束时,返回线程ID并存储到thread中attr
设置线程的属性,一般为NULL,表示采用线程默认属性start_routine
回调函数,线程要执行的函数arg
回调函数start_routine()
执行时的参数。
返回值
- 成功 0
- 失败 非0
2. 线程标识
#include <pthread.h>int pthread_equal(pthread_t t1, pthread_t t2);
pthread_t pthread_self(void);
函数
pthread_equal
判断线程ID是否相等pthread_self
返回调用线程的线程ID
3. 线程退出
3.1 线程自行退出
#include <pthread.h>void pthread_exit(void * retval);
retval
记录线程的退出信息,记录方式:
- 不可以使用线程的局部变量。
NULL
仅退出,不返回信息- 使用全局变量
- 动态分配内存
- 字符串常量
3.2 其他线程取消
#include <pthread.h>int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
函数
pthread_cancel
取消thread的线程pthread_setcancelstate
: 设置线程取消属性state
:PTHREAD_CANCEL_ENABLE
: 线程可以被取消PTHREAD_CANCEL_DISABLE
: 线程不可以被取消
oldstate
: 保持上一次取消属性的状态。
4. 连接(释放)线程
join其他线程的时候会调用
__nptl_free_tcb (pd);
释放退出线程的资源。但是NPTL模型会缓存该线程的地址空间,并不会立即
munmap
,后创建的线程会复用这块内存地址,避免了频繁的mmap
和munmap
,所以
- 使用
pthread_join
连接退出线程,后面启动的线程会复用前面joined
栈内存空间- 如果不使用
pthread_join
连接线程,那么新的线程会分配新的栈空间,从而导致内存泄漏。
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);
retval
: 存放线程返回值的地址
5. 线程分离
pthread_detach
用来设置一个线程的属性为分离属性。
#include <pthread.h>int pthread_detach(pthread_t thread);
6. 线程同步
6.1 互斥锁(mutex)
#include <pthread.h>/* 初始化线程互斥锁 */
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
/* 阻塞加锁 */
int pthread_mutex_lock(pthread_mutex *mutex);
/* 非阻塞加锁 */
int pthread_mutex_trylock( pthread_mutex_t *mutex);
/* 解锁 */
int pthread_mutex_unlock(pthread_mutex *mutex);
/* 销毁锁 */
int pthread_mutex_destroy(pthread_mutex *mutex);
6.2 条件变量(cond)
#include <pthread.h>
/* 初始化条件变量 */
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
/* 无条件等待 */
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
/* 计时条件 */
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
/* 激活一个等待该条件的线程 */
int pthread_cond_signal(pthread_cond_t *cond);
/* 激活所有等待线程 */
int pthread_cond_broadcast(pthread_cond_t *cond);
/* 销毁条件变量 */
int pthread_cond_destroy(pthread_cond_t *cond);
6.3 读写锁
- 如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!
- 如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!
#include <pthread.h>
/* 初始读写锁 */
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
/* 销毁锁 */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);