线程等待的目的
保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出
回收线程退出时的资源情况:保证当前线程推出后,创建的新线程不会复用刚才退出线程的地址空间
获得新线程退出时的结果是否时正确退出返回值
线程的状态
可结合态
这种状态下的线程是能被其他进程回收资源或被杀死的
可分离态
不能被其他进程回收资源或被杀死的,它存储的资源在它终止时由系统自动回收
默认情况下,线程是可结合态
线程分离函数
pthread_detach()
int pthread_detach(pthread_t thread);
功能
如果次线程不希望别人调用pthread_join 函数来回收,而是希望自己在运行结束时,自动回收资源调用pthread_detach
将pthread_detach()中的线程变为分离态
返回值
成功返回0;错误返回非零值
参数
thread:你要分离的那个次线程的TID
tach_struct:进程所有信息放在这里(进程号PID,地址空间,调度优先级)
线程切换的开销低:因为实质就是函数的切换
进程与线程的区别
1.进程是资源分配的最小单位,线程是资源调度的最小单位
2.每个进程有独立的地址空间,多个线程共享进程的地址空间,线程间的切换比进程间的切换开销小
3.线程的调度必须通过频繁的加锁来保持线程的同步,影响线程的并发性能
4.进程比线程更加健康,多进程之间相互独立,一个进程的异常对其他进程无影响,而一个线程的崩溃可能影响其他线程或整个程序
5.线程之间的通信方便(小数据量的),同一进程下,线程共享全局变量还有静态变量等数据,而进程之间的通信需要以通信的方式进行(IPC),不过如何处理好同步与互斥,是编写多线程程序的难点
6.多线程的代码结构比多进程的代码结构简单易读
进程同步
互斥锁
互斥锁使用步骤:
1、定义一个互斥锁(变量)pthread_mutex_t mutex
2、初始化锁:预设互斥锁的初始值 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int respthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr)
功能:初始化定义的互斥锁(就是设置互斥锁所需要的值)
返回值:总是返回0;所以这个函数不需要进行错误处理
参数:mutex:互斥锁:需要我们定义
3、加锁解锁
pthread_mutex lock(&mutex);(阻塞加锁)访问临界区加锁操作
pthread_mutex_trylock()(非阻塞加锁)当锁被占用时返回EBUSY而不是挂起等待
pthread_mutex_unlock(&mutex)访问临界区解锁
4、进程退出时销毁互斥锁
线程信号量
线程信号量的使用步骤:
1、定义信号量集合
sem_t sem【3】
线程信号量集合其实就是一个数组,数组每个元素就是一个信号量(sem【0】:第一个信号量 ; sem【1】:第二个人信号量 ; sem【2】:第三个信号量)
2、初始化集合中的每个信号量
#include<semaphore.h>
int sem_init(sem_t *sem,int pthread,unsigned int value)
功能:
初始化线程信号量集合中的某个信号量,给它设置一个初值
返回值:成功返回0,失败返回-1,errno被设置
信号量的错误号不是返回的,而是直接设置到errno
value:初始化值(对于二进制信号量来说,要么是1,要么是0)
pshared:0:给线程使用,!0可以给进程使用
3、p、v操作
P:int sem wait(sem tsem);
int sem trywait(sem tsem);
int sem timedwait(sem tsem,const struct timespec *abs timeout);
练习:线程1输出11111,线程2输出22222,线程3输出33333
4、进程结束时,删除线程信号量集合
条件变量
和互斥锁配合使用
练习:一条线程做自加,一条线程输出(当自加变量到5输出之后自加变量清零)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *add_1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
count++;
if(count == 5)
{
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void *print (void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(count != 5)
{
pthread_cond_wait(&cond, &mutex);
}
printf("cound = %d\n",count);
count = 0;
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_t id2;
int ret;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
ret = pthread_create(&id1,NULL,add_1,NULL);
if(0 != ret)
{
perror("thread create error!\n");
exit(0);
}
ret = pthread_create(&id2,NULL,print ,NULL);
if(0 !=ret)
{
perror("thread create error!\n");
exit(0);
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 0;
}
条件变量的主要作用(线程协同):主线程对count+1,次线程发现当count ==5时输出count的值并将count清零
多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程将条件准备好,然后通过条件变量将其叫醒
使用步骤:
1、定义一个条件变量
pthread_cond_t
2、初始化
pthread_cond_init(pthread_cond_t *restrict cond,const pthread condattr_t *restrict attr );
功能
初始化条件变量,与互斥锁化类似
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:成功返回0,不成功返回非零错误号
参数:
cond:条件变量
attr:属性一般是NULL
3、使用条件变量
4、删除条件变量,也需要把互斥锁删除