线程的资源
- 共享:代码段、堆、全局变量和静态变量(.dss和.data)、打开的文件描述符、信号的处理器、进程的当前目录、进程用户ID与用户组ID
- 独享:栈、信号屏蔽集、errno值,寄存器(物理寄存器的副本)、线程ID、线程的调度优先级、线程的私有数据
同一个进程的多个线程之间共享了很多资源,对这些资源的访问需要同步,防止出现不一致的情况
线程基本操作
线程标识
线程的标识为pthread_t类型,不能把它简单的当做一个整数处理,因为有些实现把它实现为一个结构。(进程的标识类型为pid_t,是一个非负整数)
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
pthread_t pthread_self(void);
线程创建
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
- 线程创建时并不能保证哪个线程先运行,是新创建的线程还是调用线程。
- 如果要先start_rtn函数传递的参数不止一个,需要把这些参数放入一个结构,然后把该结构的地址作为arg参数传入。
- 虽然每个线程有独享的errno变量,但是pthread的函数通常通过函数返回值返回错误码。
线程终止
1.终止整个进程:在线程中调用exit,_Exit,_exit
2.终止单个线程
- 从启动例程中就返回
- 被同一个进程中的其他线程取消(pthread_cancel)
- 线程调用pthread_exit
#include <pthrad.h>
void pthread_exit(void *rval_ptr);//rval_ptr指向的内存不应该是线程独享的
int pthread_join(pthread_t thread, void **rval_ptr);
int pthread_cancel(pthread_t tid);
void pthread_cleanup_push(void (*rtn)(void*), void * arg);
void pthread_cleanup_pop(int execute);
int pthread_detach(pthread_t tid);
线程间同步
对一个内存单元中存储的值进行修改分为三步:从内存单元读入寄存器,在内存器中对变量做修改,把新的值写回内存单元。如果这三个步骤不是原子操作,就可能会出现竞争(多个线程观察到的数据不一致)。
互斥量
- 互斥量是pthread_mutex_t数据类型,相当于一把锁,同时只能有一个线程获得锁
- 使用前必须初始化,动态分配的互斥量释放内存之前必须销毁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//互斥量使用前必须初始化
pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;//这种初始化方式只适用于静态分配的互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex); //如果动态分配互斥量,在释放内存前要destroy
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); //如果不能锁住互斥量,返回EBUSY
int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 指定最长阻塞时间
#include <pthread.h>
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *restric mutex, const struct timespec *restric tsptr);
读写锁
- 读写锁是pthread_rwlock_t数据类型
- 有三个状态:写模式加锁,读模式加锁,不加锁
- 一次只能有一个线程占用写模式的读写锁,多个线程可以同时占有读模式的读写锁
- 适合于对数据结构的读次数远大于写次数的场景
- 使用前必须初始化,释放内存之前必须销毁
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;//这种初始化方式只适用于静态分配的读写锁
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);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict tsptr);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict tsptr);
条件变量
- 条件变量用于一个线程向一个或者多个线程发送条件改变的信号
- 条件变量要和互斥量一同使用。线程在改变条件之前要先锁住互斥量,改变完条件之后发送信号并且把互斥量解锁。其他线程接收到通知被唤醒后,首先要尝试锁定互斥量,只有锁定了互斥量的线程可以检查条件。因此对条件的修改和检查是无竞争的,因为同时只有一个线程对条件进行操作。
-条件变量是pthread_cond_t类型
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t condv = PTHREAD_COND_INITIALIZER; //只能用于初始化静态分配的条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timewait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr); //相对时间
int pthread_cond_signal(pthread_cond_t *cond); //至少能唤醒一个等待该条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒所有等待该条件的线程
https://www.cnblogs.com/harlanc/p/8596211.html