Pthreads编程入门
本文为并行程序设计导论部分第四章的总结,读者可结合书本内容一起理解
Pthreas介绍
POSIX线程(英语:POSIX Threads,常被缩写为Pthreads)是POSIX的线程标准,定义了创建和操纵线程的一套API。
Pthreads API的一套操作函数和基本数据类型包含在pthread.h头文件中,编译时通过-lpthread将Phtreads的函数链接进来。
创建与终止
pthread对象
pthread_t数据类型是用于线程的身份标识的数据结构,与线程相关的一套函数为:
pthread_t pthread_handle;
// 第一个参数为pthread_t线程标识指针;第二个参数为设定线程属性,一般设为NULL;第三个参数为线程函数;第四个为线程函数的参数
// **注意**:线程函数的声明一般为`void* func(void* arg)`的形式
int pthread_create(pthread_t* thread_p, const pthread_attr_t* attr_p, void* (*start_routine)(void*), void* arg_p);
// 线程回收函数,等待thread_p线程运行完毕
// 其中第一个参数为回收的线程对象,第二个为线程函数的返回值
int pthread_join(pthread_t thread_p, void** ret_val_p);
//线程主动退出函数
void pthread_exit(void* ret_val_p);
函数的参数为指定的线程函数退出的返回值。
线程同步
互斥锁(mutex)
pthread_mutex_t是互斥锁在Pthreads里面的数据类型声明,互斥锁对应的一套函数为:
pthread_mutex_t mutex;
// 函数的第一个参数为互斥锁类型的指针;第二个参数的功能为指定互斥锁的属性,一般为NULL
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr_p);
// 互斥锁记得最后销毁
int pthread_mutex_destroy(pthread_mutex_t* mutex);
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread_mutex_t* mutex);
信号量(semaphore)
信号量的API不包含在Pthread的标准头文件pthread.h中,在semaphore.h头文件中。
在linux中信号量对应的一套函数为:
sem_t semaphore;
// 信号量的初始化函数,第二个参数一般为0,第三个参数为信号量的初始化数值
int sem_init(sem_t* semaphore, int shared, unsinged initial_val);
int sem_destroy(sem_t* semaphore);
// 对信号量加一
int sem_post(sem_t* semaphore);
// 对信号量减一,如果信号量为0,则阻塞等待
int sem_wait(sem_t* semaphore);
条件变量(condition)
条件变量在Pthreads中的一套函数为:
pthread_cond_t condition;
// 条件变量的初始化函数,第二个参数一般指定为NULL
int pthread_cond_init(pthread_cond_t* condition, const pthread_condattr_t* attr_p);
int pthread_cond_destroy(pthread_cond_t* condition);
// pthread_cond_wait可能被其它情况解除阻塞,被signal和broadcast函数解除的阻塞返回值为0,其它情况解除阻塞返回值不为0
int pthread_cond_wait(pthread_cond_t* condition, pthread_mutex_t* mutex);
// 在时间abstime之前等待
int pthread_cond_timedwait(pthread_cond_t* condition, pthread_mutex_t* mutex, const struct timespec* abstime);
// 发送信号
int pthread_cond_signal(pthread_cond_t* condition);
// 发送全局信号
int pthread_cond_broadcast(pthread_cond_t* condition);
注意: pthread_cond_wait只会接受阻塞等待期间发送出来的信号。
pthread_cond_wait(pthread_cond_t* condition, pthread_mutex_t* mutex) 函数相当于:
unlock(mutex);
wait_signal(condition);
lock(mutex);
条件变量的应用场景
条件变量一般用在如下的应用场景中:
// safely examine the condition, prevent other threads from
// altering it
pthread_mutex_lock (&lock);
while ( SOME-CONDITION is false)
pthread_cond_wait (&cond, &lock);
// Do whatever you need to do when condition becomes true
do_stuff();
pthread_mutex_unlock (&lock);
具体说明见:
读写锁
读写锁是一个有意思的应用场景,其实也可以通过Pthreads前面所讲的几个基本内容来实现一个读写锁。读写锁主要满足以下需求:
- 当前线程对临界区进行写操作之前,必须阻塞到那儿,直到进入临界区的线程都退出临界区。
- 多个读线程可以同时进入到临界区。
- 读线程在进入临界区之前,必须保证写线程都退出临界区。
Pthreads中对应的读写锁的API如下:
pthread_rwlock_t rwlock;
// 第二个参数的功能为读写锁设定属性,一般为NULL
int pthread_rwlock_init(pthread_rwlock_t* rwlock, pthread_rwlockattr_t* attr_p);
int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);
// 读锁
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
// 写锁
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
练习
- 思考读写锁存在的意义。
- 简单编程实现Pthread的读写锁功能。
- 思考信号量与条件变量的区别与联系。(针对应用场景)
- 动手实现线程池。