线程在运行的过程中总是同时发生的,这会对现实的需求造成干扰,因此我们定义了多种函数接口,来解决线程在运行过程中存在的资源竞争以及运行先后顺序的问题。
之前学习到线程可以通过手动pthread_join手动回收线程的空间,和进程中的wait作用类似,然而,在进程的创建过程中可以使用第二个参数来设置分离属性,达到自动回收线程空间的效果,然而这个效果也需要考虑现实情况来用。
1.线程分离属性:
线程结束后,自动回收线程空间pthread_attr_init
int pthread_attr_init(pthread_attr_t *attr);
功能:
线程属性初始化pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
功能:
线程属性销毁pthread_attr_setdetachstate
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
功能:
设置分离属性
PTHREAD_CREATE_DETACHED 分离属性
PTHREAD_CREATE_JOINABLE 加入属性(默认)练习:定义一个学生结构体
struct student
{
char name[32];
char sex;
int age;
int score;
};创建两个线程,线程1负责从终端接收学生信息
线程2负责将学生信息打印在终端
为了避免资源竞争采用互斥锁:
2.线程互斥:
1.互斥锁:防止资源竞争
2.函数接口:
pthread_mutex_init:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能:
互斥锁初始化
参数:
mutex:互斥锁空间首地址
attr:互斥锁的属性(默认为NULL)
返回值:
成功返回0
失败返回错误码pthread_mutex_destroy:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
互斥锁销毁
参数:
mutex:互斥锁空间首地址
返回值:
成功返回0
失败返回错误码pthread_mutex_lock:
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
上锁pthread_mutex_unlock:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
解锁3.临界资源、临界区:
加锁解锁中间的代码称为临界资源、临界区
同一时刻临界资源不能同时执行,只能执行其中一个临界资源代码4.原子操作:
CPU最小的一次不能被任务调度打断的操作称为原子操作5.互斥锁只能解决资源竞争的问题,无法同步代码(没有先后执行的顺序关系)
上锁引发的意外情况:
3.死锁:
多线程操作互斥锁,导致多个线程均无法向下执行的状态称为死锁状态简称为死锁死锁产生的四个必要条件:
1.互斥条件
2.不可剥夺条件
3.请求保持
4.循环等待避免产生死锁:
1.pthread_mutex_trylock 替代 pthread_mutex_lock
2.加锁顺序保持一致
4.信号量:
信号量是一种资源,可以被初始化、申请、释放、销毁P操作:申请资源
V操作:释放资源sem_init
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:
初始化信号量
参数:
sem:信号量空间首地址
pshared:
0 一个进程中的所有线程间共享
非0 进程间共享
value:
初始化的值
返回值:
成功返回0
失败返回-1
sem_destroy:
int sem_destroy(sem_t *sem);
功能:
信号量的销毁
参数:
sem:信号量空间首地址
返回值:
成功返回0
失败返回-1sem_wait:
int sem_wait(sem_t *sem);
功能:
申请信号量sem_post:
int sem_post(sem_t *sem);
功能:
释放信号量