单执行流的进程,其PID和LWP相同,所产生的次线程LWD开始与PID不同。OS内核区别执行流其实是看LWP,从此PID的主要作用是查看该资源是属于哪个进程的。
其中的 && 相当于语言中的逻辑与,前半部分执行成功才执行后半部分
主线程结束,进程就退出了!因为进程是承担系统资源的基本实体!主线程退出,其他线程也就退出了。
线程退出的方案-用pthread_join()+return(void*) number code接收,必须有这个,不然也会形成僵尸线程,默认是用阻塞方式等待接收。
用pthread_join来退出线程,实验现象可以看到主线程等待了次线程退出返回10,所以pthread_join可以回收退出线程的资源
如下图所示,线程出现变异错误时,主线程就算使用了pthread_join来接受返回码,也是收不到的,直接报错,因为之前说过:“只要有一个线程出错,整个进程都回崩溃”
退出线程的方法1-用exit() ///其实退出的是整个进程
可以看到exit的作用还是终止进程,而不简单终止线程。
退出线程的方法3-用pthread_exit((void*) ) ///和直接用return一样
这个方法和return一样的,都是这个线程自己要求返回。
退出线程的方法4-用pthread_cancle(tid) ///要求让某个线程退出
这种方法可以要求让某个线程退出,退出码为-1
歪门邪道:进程内部的线程是平等的,其实次线程也可以用上述相关方法杀掉主线程,做是可以做,但是没意义。也可以自杀:pthread_cancle+pthread_self()。
主线程可以管理其他次线程,如同父进程可以管理子进程。
线程分离
分离之后,这个线程也就不贵主线程管了,实验现象证明线程退出的时候,主线程也没有接收到它的退出码10。可以自己分离自己,也可以用主线程分离次线程。分离的退出时候,资源自动释放。
使用场景:服务器给客户返回网页的时候,创建线程去给客户返回网页,然后这个线程自己分离,完了结束自己释放资源。主线程不用去关心用户申请成功没有,失败了再让他自己请求一次。
注意点:被分离的线程依然遵循基本规律:线程的出错影响整个进程,即使整个线程被分离,但是它的崩溃出错会导致整个进程报错。
实验:更改全局变量,查看对线程的影响
创建一个线程1,线程2,设置一个全局变量a = 10,10秒后主线程把a更改为100,三者之后还是都可以读到a为100
所有代码,所有数据被所有线程共享。但是不一定所有的共享资源都被所有线程访问。
临界、互斥、锁
会被多个线程同时访问的资源成为临界资源,代码中,访问临界资源的相关代码段落,被称为临界区。
pthread_mutex_t lock 互斥锁
用互斥锁简单模拟抢票
初始化互斥量有两种方法:
方法1,静态分配: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
方法2,动态分配: int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数:mutex:要初始化的互斥量 attr:NULL
销毁互斥量需要注意:
- 使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁
- 不要销毁一个已经加锁的互斥量
- 已经销毁的互斥量,要确保后面不会有线程再尝试加锁
互斥量加锁和解锁
- int pthread_mutex_lock(pthread_mutex_t *mutex);
- int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 返回值:成功返回0,失败返回错误号
调用 pthread_ lock 时,可能会遇到以下情况:
- 互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功
- 发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互斥量,
- 那么pthread_ lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。