目录
[2. Linux 进程 vs 线程 -- 哪些资源共享,哪些独占](#2. Linux 进程 vs 线程 -- 哪些资源共享,哪些独占)
[2.1 共识](#2.1 共识)
[2.2 进程和线程](#2.2 进程和线程)
[2.3 进程的多个线程共享](#2.3 进程的多个线程共享)
[2.4 如何看待之前的单进程?](#2.4 如何看待之前的单进程?)
[3. Linux线程控制](#3. Linux线程控制)
[3.1 直接使用各个线程控制的接口](#3.1 直接使用各个线程控制的接口)
[3.2 创建线程](#3.2 创建线程)
[3.3 验证历史讲理论的各个细节](#3.3 验证历史讲理论的各个细节)
[3.3.1 全局变量共享:](#3.3.1 全局变量共享:)
[3.3.2 多线程其它函数共享:](#3.3.2 多线程其它函数共享:)
[3.3.3 堆区也是共享的:](#3.3.3 堆区也是共享的:)
[3.3.4 main函数执行完直接先退出的话,会发生什么??](#3.3.4 main函数执行完直接先退出的话,会发生什么??)
[3.4 pthread_join,是在线程库中等待线程的一个函数。](#3.4 pthread_join,是在线程库中等待线程的一个函数。)
[3.4.1 创建多个线程,等待多个线程:](#3.4.1 创建多个线程,等待多个线程:)
[3.5 验证线程崩溃问题:](#3.5 验证线程崩溃问题:)
[3.6 线程的退出方法:(三个方法)](#3.6 线程的退出方法:(三个方法))
[方法1. return nullptr;](#方法1. return nullptr;)
[exit(10); ( 线程的退出不能使用exit() )](#exit(10); ( 线程的退出不能使用exit() ))
[方法2. pthread_exit()](#方法2. pthread_exit())
[pthread_self(); 自己获取自己的线程id](#pthread_self(); 自己获取自己的线程id)
方法3:pthread_cancel(要取消的线程id):可以让一个线程去取消另一个线程
[4. 线程的传参和返回值](#4. 线程的传参和返回值)
[4.1 返回值](#4.1 返回值)
[4.1.1 从编码层面上理解返回值](#4.1.1 从编码层面上理解返回值)
[4.1.2 pthread_join() 第二个参数的问题](#4.1.2 pthread_join() 第二个参数的问题)
2. Linux 进程 vs 线程 -- 哪些资源共享,哪些独占
2.1 共识
- 进程间具有独立性。进程更强调独占,偶尔要进行资源共享
- 线程共享地址空间,也就共享进程资源。线程更强调资源共享,偶尔要进行资源独占
2.2 进程和线程
- 进程是资源分配的基本单位
- 线程是调度的基本单位
- 线程共享进程数据,但也拥有自己的一部分 "私有" 数据:(后面会提到,其实线程并没有私有的数据,只不过是将这部分资源分配给线程了,别人想拿的话其实也是可以拿的)
- 线程ID (重点)
- 一组寄存器,线程的上下文数据 (重点) ---> 说明线程是要被调度的
- 栈 (重点) ---> 说明线程除了要被调度、切换,线程本身在被运行时会产生临时数据,线程自己也有函数调用,栈帧结构
- errno
- 信号屏蔽字
- 调度优先级
2.3 进程的多个线程共享
同一个进程内的多个线程,大部分是资源全都是共享的。所有的轻量级进程 / 线程 的概念都属于同⼀地址空间,因此 Text Segment 、 Data Segment 都是共享的,如果定义⼀个函数,在各线程中
都可以调⽤,如果定义⼀个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
- 文件描述符表 (一个进程打开文件会有文件描述符表,每一个进程都会指向主线程的同样的一张文件描述符表,新的task_struct的大部分属性同样来自于主线程,从主线程拷贝到新线程中的)
- 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
- 当前的工作目录
- 用户id 和 组id
线程和进程的关系:

2.4 如何看待之前的单进程?
之前的单进程,是具有一个线程执行流的进程
3. Linux线程控制
3.1 直接使用各个线程控制的接口
- 与线程相关的函数是库函数,都遵守POSIX的标准,命名上都是以"pthread_" 打头
- 使用这些函数,都要包含头文件<pthread.h>
- 链接这些线程函数库时要使用编译器命令的 "-lpthread" 的选项
3.2 创建线程
创建线程使用的函数:pthread_create

bash
#Makefile
test_thread : testThread.cc
g++ -o $@ $^ -lpthread -std=c++11
.PHONY:clean
clean:
rm -f test_thread
cpp
//testThread.cc
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void* args)
{
std::string name = static_cast<const char*>(args);
//新线程
while(true)
{
printf("new thread...\n");
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
//主线程
while(true)
{
printf("main thread...\n");
sleep(1);
}
}

运行结果:

我们编程时认为的两个线程,其实在内核中对应的就是两个轻量级进程。


pthread库头文件就在以下目录下:

所以不用告诉我在哪里找,所对应的库文件:



打印一下 tid :
cpp
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
printf("main create a new thread, new thread id is: %lu\n", tid);
//主线程
while(true)
{
printf("main thread...\n");
sleep(1);
}
}
运行结果:
打印出来的值很大!!以16进制输出


3.3 验证历史讲理论的各个细节
3.3.1 全局变量共享:
cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
void *thread_routine(void* args)
{
std::string name = static_cast<const char*>(args);
//新线程
while(true)
{
printf("new thread..., gval: %d, &gval: %p\n", gval, &gval);
gval++;
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
//主线程
while(true)
{
printf("main thread..., gval: %d, &gval: %p\n", gval, &gval);
sleep(1);
}
}
定义一个全局变量,在新线程中对全局变量做++,最后的结果是全局变量共享:

3.3.2 多线程其它函数共享:
cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
std::string fun()
{
return "我是另一个函数";
}
void *thread_routine(void* args)
{
std::string name = static_cast<const char*>(args);
//新线程
while(true)
{
printf("new thread..., gval: %d, &gval: %p , %s\n", gval, &gval, fun().c_str());
gval++;
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
//主线程
while(true)
{
printf("main thread..., gval: %d, &gval: %p, %s\n", gval, &gval, fun().c_str());
sleep(1);
}
}
运行结果:

多线程其他函数共享 ---> 所以函数重入的概念 就有了!!!
新线程在调用该函数,主线程也在调用该函数,此时两个执行流同时进入同一个函数,这个现象就叫做函数被重入了!!如果在某个时刻的重入导致了系统出错,那么这个函数就是不可重入函数;如果无论在什么情况下重入都不会出错,那么它是可重入函数。
在多进程中,函数不存在重入的问题。
3.3.3 堆区也是共享的:
补充:一旦线程被创建了,主线程和新线程在OS内部都是两个task_struct,task_struct 会以相同优先级的方式链入到大O(1)的算法中,放在同一张哈希表中的链表中当中,所以一般是不会规定主线程和新线程的顺序,但是今天在之后的代码中我们想让新线程将空间创建出来,所以让主线程中执行 sleep(2); 语句。
cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; //定义一个指针
std::string fun()
{
return "我是另一个函数";
}
void *thread_routine(void* args)
{
std::string name = static_cast<const char*>(args);
data = new int(10);
//新线程
while(true)
{
printf("new thread..., gval: %d, &gval: %p , %s, data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
gval++;
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
//主线程
sleep(2);
while(true)
{
printf("main thread..., gval: %d, &gval: %p, %s,data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
sleep(1);
}
}
运行结果:

原则上,堆空间也是共享的。为什么说的是原则上呢??新线程申请堆空间,是不会让全局指针指向堆空间的,是会在新线程内部定义自己的指针。虽然这个堆空间是新线程内部自己申请的,但是如果你想要访问的话,是有办法来访问到的!!!
cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; //定义一个指针
std::string fun()
{
return "我是另一个函数";
}
void *thread_routine(void* args)
{
std::string name = static_cast<const char*>(args);
// 堆空间,就是该线程申请的,往往只需要让对应的线程知道
// 这部分堆空间起始虚拟地址,就可以叫做这个堆是该线程拥有的
int *data = new int(10);
//新线程
while(true)
{
printf("new thread..., gval: %d, &gval: %p , %s, data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
gval++;
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; //避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
//主线程
sleep(2);
while(true)
{
printf("main thread..., gval: %d, &gval: %p, %s,data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
sleep(1);
}
}
其实,这个堆空间往往是全局的,只不过在申请的时候只有该线程知道罢了,其它线程不知道,对于该线程来说这个堆空间就是属于该线程的。
3.3.4 main函数执行完直接先退出的话,会发生什么??
cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; // 定义一个指针
std::string fun()
{
return "我是另一个函数";
}
// 新线程
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
// 堆空间,就是该线程申请的,往往只需要让对应的线程知道
// 这部分堆空间起始虚拟地址,就可以叫做这个堆是该线程拥有的
int *data = new int(10);
int cnt = 10;
while (cnt--)
{
printf("new thread..., gval: %d, &gval: %p , %s, data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
gval++;
sleep(1);
}
return nullptr; //如果线程执行完了自己的入口函数,表明该线程结束退出
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; // 避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
sleep(3);
return 0; //如果main函数结束,表示主线程结束,同时也表示,当前进程结束
}
运行结果:


主线程退出,新线程自己也主动退出了。
主线程退出,表示进程结束,进程结束 ---- 释放资源!!
结论是:进程结束,所有的线程全部退出,哪怕没有执行完!!!
所以,在多线程代码中,主/新线程谁先运行不关注,但是,往往我们想让主线程最后退出!!!
所以:线程也要进行等待,类似进程的wait!
要对新线程进行等待:
1. 主线程可能先退出,进而导致整个进程全部都挂掉
**2. 也会造成类似僵尸进程的问题!!**之前进程的退出时,所有的资源都可以被释放了,唯独要保留PCB,线程也是一样的,但是在linux系统中不存在线程,只存在轻量级进程。一旦线程退出,轻量级进程是看不到的。所以查不到僵尸进程这样的概念,也查不到僵尸轻量级进程这样的概念。
3.4 pthread_join,是在线程库中等待线程的一个函数。


cpp
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; // 定义一个指针
std::string fun()
{
return "我是另一个函数";
}
// 新线程
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
// 堆空间,就是该线程申请的,往往只需要让对应的线程知道
// 这部分堆空间起始虚拟地址,就可以叫做这个堆是该线程拥有的
int *data = new int(10);
int cnt = 5;
while (cnt--)
{
printf("new thread..., gval: %d, &gval: %p , %s, data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
gval++;
sleep(1);
}
return nullptr; //如果线程执行完了自己的入口函数,表明该线程结束退出
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; // 避免警告
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
pthread_join(tid, nullptr);
printf("main end...\n");
return 0; // 如果main函数结束,表示主线程结束,同时也表示,当前进程结束 --- 释放资源
// 结论是:进程结束,所有线程全部退出,哪怕没有执行完
}
运行结果:

3.4.1 创建多个线程,等待多个线程:
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; // 定义一个指针
std::string fun()
{
return "我是另一个函数";
}
// 新线程
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
// 堆空间,就是该线程申请的,往往只需要让对应的线程知道
// 这部分堆空间起始虚拟地址,就可以叫做这个堆是该线程拥有的
int *data = new int(10);
int cnt = 5;
while (cnt--)
{
printf("new thread..., gval: %d, &gval: %p , %s, data: %p, %d\n",
gval, &gval, fun().c_str(), data, *data);
gval++;
sleep(1);
}
return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
}
int gnum = 10;
int main()
{
std::vector<pthread_t> tids;
for (int i = 0; i < gnum; i++)
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread-1");
(void)n; // 避免警告
tids.push_back(tid);
}
for (auto &tid : tids)
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
for (auto &tid : tids)
{
pthread_join(tid, nullptr);
printf("new thread end...,%lu\n", tid);
}
printf("main end...\n");
return 0; // 如果main函数结束,表示主线程结束,同时也表示,当前进程结束 --- 释放资源
// 结论是:进程结束,所有线程全部退出,哪怕没有执行完
}
运行结果:


接下来,要给线程传参:
运行结果:

多运行几次,每次运行出来的结果都不同:

为什么会出现这样的问题呢??

正确书写:
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; // 定义一个指针
std::string fun()
{
return "我是另一个函数";
}
// 新线程
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
// 堆空间,就是该线程申请的,往往只需要让对应的线程知道
// 这部分堆空间起始虚拟地址,就可以叫做这个堆是该线程拥有的
// int *data = new int(10);
int cnt = 5;
while (cnt--)
{
printf("new thread is running, name is : %s\n",name.c_str());
sleep(1);
}
return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
}
int gnum = 5;
int main()
{
std::vector<pthread_t> tids;
for (int i = 0; i < gnum; i++)
{
pthread_t tid;
//构建新线程的名称
// char idbuffer[64];
char *p = new char[64]; //申请一段堆空间
snprintf(p, 64, "thread-%d",i+1);
int n = pthread_create(&tid, nullptr, thread_routine, p);
(void)n; // 避免警告
tids.push_back(tid);
}
sleep(1);
for (auto &tid : tids)
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
for (auto &tid : tids)
{
pthread_join(tid, nullptr);
printf("new thread end...,%lu\n", tid);
}
printf("main end...\n");
return 0; // 如果main函数结束,表示主线程结束,同时也表示,当前进程结束 --- 释放资源
// 结论是:进程结束,所有线程全部退出,哪怕没有执行完
}
运行结果:

从结果中可以看出来:谁先运行并不确定。这5个进程谁先调度,谁就先运行。
多线程的模板 ------ 就是 for 循环进行创建和等待线程。
3.5 验证线程崩溃问题:
新线程中会一个线程有野指针的问题,但是主线程中是没有问题的:
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
volatile int gval = 100;
int *data = nullptr; // 定义一个指针
std::string fun()
{
return "我是另一个函数";
}
// 新线程
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
int cnt = 10;
while (true)
{
printf("new thread is running, name is : %s\n", name.c_str());
cnt--;
if (cnt == 3)
{
printf("%s is dead...\n", name.c_str());
int *p = nullptr;
*p = 0;
}
sleep(1);
}
return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
}
int gnum = 5;
int main()
{
std::vector<pthread_t> tids;
for (int i = 0; i < gnum; i++)
{
pthread_t tid;
char *p = new char[64]; // 申请一段堆空间
snprintf(p, 64, "thread-%d", i + 1);
int n = pthread_create(&tid, nullptr, thread_routine, p);
(void)n; // 避免警告
tids.push_back(tid);
}
sleep(1);
for (auto &tid : tids)
printf("main create a new thread, new thread id is: 0x%lx\n", tid);
for (auto &tid : tids)
{
pthread_join(tid, nullptr);
printf("new thread end...,%lu\n", tid);
}
printf("main end...\n");
return 0; // 如果main函数结束,表示主线程结束,同时也表示,当前进程结束 --- 释放资源
// 结论是:进程结束,所有线程全部退出,哪怕没有执行完
}
运行结果:

一个线程崩溃,其它的线程包括主线程都是会崩溃的,证明了线程在运行的时候健壮性降低,线程一旦出现异常,进程就会跟着崩溃,一旦进程崩溃,其它线程全部崩溃。
在执行代码的时候,多线程中,有一个线程触发异常,当前进程会收到信号,其实会把信号发给每一个线程,每一个线程全部都会退,进程退出时,退出信号是segmentation fault。线程退出的导致原因是什么呢?由当前的bash获得当前的进程的退出码得知的,bash不知道是哪一个子进程触发的,但是也不需要知道。
3.6 线程的退出方法:(三个方法)
方法1. return nullptr;
如果线程执行完了自己的入口函数,表明该线程结束退出
exit(10); ( 线程的退出不能使用exit() )
用来进行终止进程的!!任何一个线程,调用exit,都会导致进程退出,变相的导致所有的线程退出!!
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s\n", name.c_str());
sleep(1);
break;
}
// return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
exit(10);
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
int m = pthread_join(tid, nullptr);
(void)m;
printf("main thread end...\n");
return 0;
}
运行结果:

所以,在线程中是不能用exit的!!!
方法2. pthread_exit()

cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s\n", name.c_str());
sleep(1);
break;
}
// return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
// exit(10); //用来进行终止进程的!!任何一个线程,调用exit,都会导致进程退出,变相的导致所有的线程退出!!
pthread_exit(nullptr);
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
int m = pthread_join(tid, nullptr);
(void)m;
sleep(3);
printf("main thread end...\n");
return 0;
}


新线程能不能知道自己的id是多少??主线程不也是一个线程吗?他是否有线程id呢?
pthread_self(); 自己获取自己的线程id
谁调用整个函数,就返回谁的线程id

cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
break;
}
// return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
// exit(10); //用来进行终止进程的!!任何一个线程,调用exit,都会导致进程退出,变相的导致所有的线程退出!!
// pthread_exit(nullptr);
return nullptr;
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
printf("main thread create done, main thread id: 0x%lx, new thread id: 0x%lx\n", pthread_self(),tid);
int m = pthread_join(tid, nullptr);
(void)m;
sleep(3);
printf("main thread end...\n");
return 0;
}

方法3:pthread_cancel(要取消的线程id):可以让一个线程去取消另一个线程


cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
// break;
}
// return nullptr; // 如果线程执行完了自己的入口函数,表明该线程结束退出
// exit(10); //用来进行终止进程的!!任何一个线程,调用exit,都会导致进程退出,变相的导致所有的线程退出!!
// pthread_exit(nullptr);
// return nullptr;
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
printf("main thread create done, main thread id: 0x%lx, new thread id: 0x%lx\n", pthread_self(),tid);
sleep(2);
pthread_cancel(tid);
printf("cancel target thread...\n");
int m = pthread_join(tid, nullptr);
(void)m;
sleep(3);
printf("main thread end... m is: %d\n",m);
return 0;
}
运行结果:

自己可以把自己取消吗??------ 可以的!!
cpp
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
pthread_cancel(pthread_self());
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
printf("main thread create done, main thread id: 0x%lx, new thread id: 0x%lx\n", pthread_self(),tid);
sleep(2);
int m = pthread_join(tid, nullptr);
(void)m;
sleep(3);
printf("main thread end... m is: %d\n",m);
return 0;
}
运行结果:


结论:
- 方法1 和 方法2 推荐在自己的线程中使用
- 方法3 本来就是main取消其它线程的 ---- 最佳实践
4. 线程的传参和返回值
4.1 返回值
4.1.1 从编码层面上理解返回值
第一个:
cpp
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
// pthread_cancel(pthread_self());
break;
}
return (void*)10; // 数字10在C语言中叫做字面值,类型是:int,占4字节,会被硬编码到代码当中,跟平时定义的字符串是一样的 "hello sy!"
// 数字10强转为 void *,充当返回值,就返回出去了
}
第二个:
要获取对应的返回值,想通过函数获取,pthread_join() 第二个参数是一个输出型参数,想通过函数的方式把线程退出时的返回值带出来,返回值是一个 void* 类型,要用函数的方式将返回值带出来:
首先也得有一个 void*
cpp
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread -1");
(void)n; // 避免警告
printf("main thread create done, main thread id: 0x%lx, new thread id: 0x%lx\n", pthread_self(),tid);
sleep(2);
void *ret;
int m = pthread_join(tid, &ret);
(void)m;
if(m == 0)
{
printf("new thread return val: %lld\n",(long long)ret);
}
sleep(3);
printf("main thread end... m is: %d\n",m);
return 0;
}
运行结果:

修改一下返回值:
cpp
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
// pthread_cancel(pthread_self());
break;
}
pthread_exit((void*)20);
}
运行结果:

此时拿到的就是20。
所以创建线程是为了给我完成一件事的,怎么知道事情完成的怎么样了??
cpp
void *thread_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
printf("new thread is running, name is : %s, new thread id: 0x%lx\n", name.c_str(), pthread_self());
sleep(1);
// pthread_cancel(pthread_self());
break;
}
pthread_exit((void*)0); //代码正确执行完
pthread_exit((void*)1); //代码执行完,不对的原因
pthread_exit((void*)2); //代码执行完,不对的原因
pthread_exit((void*)3); //代码执行完,不对的原因
pthread_exit((void*)4); //代码执行完,不对的原因
}
不对的原因是什么,此时就可以返回给主线程了。主线程通过pthread_join()就能得知新线程执行的结果:代码跑完,结果对还是不对?
之前进程的退出信息 = 信号 + 退出码,今天pthread_join()返回什么,我们就拿到什么。难道,多线程这里,不考虑所谓的异常吗??
4.1.2 pthread_join() 第二个参数的问题
int pthread_join(pthread_t thread, void **retval);
1. 获取新线程的执行结果,需要考虑新线程的异常问题吗??---- 不用考虑了!!!因为没机会考虑!!!
一旦要等的目标线程内部出现了异常,除0,野指针...线程一旦出现异常,整个进程就全部跟着崩溃了!!主线程 pthread_join() 根本就没有机会返回,所以线程 pthread_join() 不提供所谓获取退出信号的接口。异常属于进程异常,是由父进程关心,通过wait()关心。所以,pthread_join() 考虑常规情况即可。
所以 int pthread_join(pthread_t thread, void **retval); 不再做位图设置。对方给你返回什么,你就拿什么就好了。
2. 新线程是如何把自己的返回值,交给父进程的,父进程如何通过 pthread_join,获得指定子进程的退出信息??
第一讲:

