# 创建线程
/* 查看当前线程ID */
typedef unsigned long int pthread_t;
pthread_t pthread_self(void);
/* 创建进程 */
union pthread_attr_t
{
char __size[__SIZEOF_PTHREAD_ATTR_T];
long int __align;
};
typedef union pthread_attr_t pthread_attr_t;
int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
/*
Description:
newthread:传出参数,创建的新线程ID
addr:线程的属性,一般情况使用默认值即可,NULL
start_routine:函数指针,创建出的子进程的处理函数,也就是在子线程中需要执行的函数
arg:作为实参传递到start_routine指针指向的函数内部
Return Value:
线程创建成功返回0,否则返回对于的错误码
*/
# 线程退出
void pthread_exit(void *retval);
/*
Description:
只要调用该函数,当前线程立马退出,并且不影响其他线程的运行,不管是在子进程还是主进程中都可以使用
retval:线程退出时携带的数据,当前子线程的主进程会得到该数据。如果不需要,指定为NULL。
*/
# 线程回收
int pthread_join(pthread_t thread, void **retval);
/*
Description:
用于在子进程退出后,主进程回收子进程的内核资源。该函数为一个堵塞函数,如果子进程还在运行,调用该函数就会堵塞,子线程退出函数解除堵塞,并将线程占用的内核资源回收。
thread:子进程的进程ID
retval:二级指针,指向一级指针的地址,是一个传出参数,这个地址中存储了pthread_exit()传递出的数据,如果不需要这个参数,可以指定为NULL。
Return Value:
线程回收成功返回0,回收失败返回错误码。
*/
# 线程分离
在某些情况下,程序中的主线程有属于自己的业务处理流程,如果让主线程负责子线程的资源回收,调用 pthread_join()
,只要子线程不退出,主线程就会被一直堵塞,主线程的任务也就不能被执行。
int pthread_detach(pthread_t thread);
/*
Description:
调用线程分离函数之后,指定的子线程就可以和主线程分离,当子进程退出的时候,其占用的内核资源就会被系统的其他线程接管并回收。线程分离之后,主线程中使用的pthread_join()就回收不到子线程的资源了。
thread:子线程ID
*/
# 线程取消
int pthread_cancel(pthread_t thread);
/*
Description:
在一个线程中杀死另外一个线程。使用这个函数杀死一个线程需要分两步:
1. 在线程A中调用线程取消函数pthread_cancel(),指定杀死线程B。
2. 线程B中执行一次系统调用时才会被杀死,否则仍然存活。
*/
# 线程 ID 比较
int pthread_equal(pthread_t t1, pthread_t t2);
/*
Description:
t1,t2为需要比较的两个线程ID。
Return Value:
如果两个线程ID相等返回一个非0值,如果不等则返回0
*/
# 线程同步
# 互斥锁
互斥锁是线程同步最常用的一种方式,通过互斥锁可以锁定一个代码块。被锁定的代码块,所以线程只能顺序执行。
pthread_mutex_t mutex;
/* 初始化互斥锁 */
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *attr);
/*
mutex: 互斥锁变量地址
attr: 互斥锁的属性,一般使用默认属性即可,这个参数指定为NULL
返回0,则初始化成功,否则返回错误码
*/
/* 释放互斥锁 */
int pthread_mutex_destroy(pthread_mutex_t *mutex);
/* 上锁 */
int pthread_mutex_lock(pthread_mutex_t *mutex);
/*
Description:
这个函数被调用,实现会判断参数mutex互斥锁中的状态是不是锁定状态:
- 没有锁定,则这个线程可以加锁成功,这个锁会记录是哪一个线程加锁成功了
- 如果被锁定,其他线程加锁就失败了,这些线程都会被堵塞在这把锁上
- 当这把锁被解开之后,这些堵塞在锁上的线程就会解除堵塞,并且这些线程通过竞争的方式对这把锁加锁,没抢到锁的进程继续堵塞
*/
/* 尝试加锁 */
int pthread_mutex_trylock(pthread_mutex_t *mutex);
/*
Description:
尝试对mutex互斥锁进行加锁:
- 若互斥锁没有被锁定,线程加锁成功
- 若互斥锁被锁定,调用这个函数加锁的线程,不会被堵塞,加锁失败直接返回错误码
*/
/* 解锁 */
int pthread_mutex_unlock(pthread_mutex_t *mutex);
/*
Description:
并不是所以的线程都可以对互斥锁解锁,那个线程加的锁,那个线程才可以解锁。
*/
# 死锁
当多个线程访问共享资源,需要加锁,如果锁使用不当,就会造成死锁这种现象。
# 读写锁
读锁是共享的,写锁是独占的;写锁比读锁优先级高;如果临界区涉及大量的读操作,使用读写锁比使用互斥锁效率高,而只有少量的读操作,则互斥锁和读写锁效率差异不大
pthread_rwlock_t rwlock; | |
/* 初始化读写锁 */ | |
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); | |
/* 销毁读写锁 */ | |
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); | |
/* 加读锁 */ | |
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); | |
/* 尝试加读锁,加锁失败不堵塞 */ | |
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); | |
/* 加写锁 */ | |
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); | |
/* 尝试加写锁,加锁失败不堵塞 */ | |
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); | |
/* 解锁(读锁 / 写锁) */ | |
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); |
# 条件变量
一般情况下条件变量用于处理生产者和消费者模型,并且和互斥锁配合使用。条件变量类型为 pthread_cond_t
,被条件变量堵塞的线程以及线程信息会被记录到这个变量中,以便在解除堵塞时使用。
pthread_cond_t cond; | |
/* 初始化 */ | |
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condaddr_t *restrict attr); | |
/* 销毁释放资源 */ | |
int pthread_cond_destroy(pthread_cond_t *cond); | |
/* 堵塞当前线程 / 进程 */ | |
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *mutex); | |
struct timespec{ | |
time_t tv_sec; | |
long tv_nsec; | |
}; | |
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *mutex, const struct timespec *restrict abstime); | |
/* 唤醒堵塞在条件变量上的一个线程 */ | |
int pthread_cond_signal(pthread_cond_t *cond); | |
/* 唤醒所以堵塞在条件变量上的线程 */ | |
int pthread_cond_broadcast(pthread_cond_t *cond); |
# 信号量
#include <semaphore.h> | |
sem_t sem; | |
int sem_init(sem_t *sem, int pshared, unsigned int value); | |
/* | |
sem: 信号量变量地址 | |
pshared: 0 表示线程同步;非 0 表示进程同步 | |
value: 初始化当前信号量拥有的资源数 | |
*/ | |
int sem_destroy(sem_t &sem); | |
int sem_wait(sem_t *sem); | |
int sem_try_wait(sem_t *sem); | |
/* 产看信号量 sem 当前拥有的资源个数,通过第二个参数传出(返回值也可以) */ | |
int sem_getvalue(sem_t *sem, int *sval); | |
int sem_post(sem_t *sem); |