朋友们、伙计们,我们又见面了,本期来给大家带来线程控制相关代码和知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通****
数据结构专栏:数据结构****
个 人 主 页 :stackY、****
C + + 专 栏 :C++****
Linux 专 栏 :Linux****
目录
[1. 创建线程](#1. 创建线程)
[1.1 引入线程库](#1.1 引入线程库)
[2. 获取线程id](#2. 获取线程id)
[3. 线程终止](#3. 线程终止)
[4. 线程等待](#4. 线程等待)
[5. 线程的分离](#5. 线程的分离)
[6. 线程的取消](#6. 线程的取消)
1. 创建线程
在使用线程有关函数接口时需要引入头文件pthread.h
创建一个新的线程:
cppint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void*), void *arg);
参数:
- thread:返回新线程ID
- attr:设置线程的属性,attr为NULL表示使用默认属性
- start_routine:是个函数地址,线程启动后要执行的函数
- arg:传给线程启动函数的参数
返回值:
成功返回0,失败返回错误码。
代码演示:
cpp#include <iostream> #include <unistd.h> #include <pthread.h> #include <sys/types.h> #include <unistd.h> // 新线程 void *ThreadRoutine(void *arg) { const char *threadname = (const char *)arg; while (true) { std::cout << "I am a new thread: " << threadname << ", pid: " << getpid() << std::endl; sleep(1); } } int main() { pthread_t tid; // 创建线程 pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread 1"); // 主线程 while (true) { std::cout << "I am main thread" << ", pid: " << getpid() << std::endl; sleep(1); } return 0; }
1.1 引入线程库
当我们直接编译时可以发现报错,明明已经引入了线程相关的头文件,为什么还会找不到该函数呢?
因为Linux没有真正的线程,只有轻量级进程的概念,所以Linux OS只会提供轻量级进程创建的系统调用,不会直接提供线程的创建的接口,Linux的线程是通过pthread原生线程库实现的,所以我们需要在编译选项中引入线程库
Makefile:
cpptestThread:testThread.cc g++ -o $@ $^ -std=c++11 -lpthread .PHONY:clean clean: rm -f testThread
引入线程库之后再编译就不会出现报错了。
2. 获取线程id
获取自己的线程id:
cpppthread_t pthread_self(void);
哪个线程调用该函数就可以返回哪个线程的id。
当我们将线程id获取并打印之后可以发现,线程id和线程的LWP毫无关系,并且线程id是一个比较大的数:
如果我们将这个id以十六进制的格式打印就会发现,线程的id本质上就是一个地址!
3. 线程终止
线程终止一共有三种方法:
- ① 直接在新线程中返回;
- ② 使用pthread_exit函数;
- ③ 使用pthread_cancel函数(线程的取消)。
线程终止可以直接在新线程中返回即可,还可以通过函数接口的方式进行终止:
cppvoid pthread_exit(void *retval);
注意:不能使用exit()来终止线程,这样会使整个进程退出。
参数:
- retval:可以设为空,也可以设置退出信息
4. 线程等待
线程和进程一样也是需要进行等待的,如果不等待就会发生和僵尸进程一样的情况(线程退出但是它的空间没有被释放),并且我们也会需要知道线程的退出信息,所以就需要有等待线程的接口。
cppint pthread_join(pthread_t thread, void **retval);
参数:
- thread:要等待的线程ID
- retval:它指向一个指针,后者指向线程的返回值(获取退出信息),也可以设为空
返回值:
成功返回0,失败返回错误码
代码演示:获取返回值信息和线程终止接口配合使用
cpp// 新线程 void *ThreadRoutine(void *arg) { int cnt = 1; const char *threadname = (const char *)arg; while (true) { pthread_t id; // 获取线程id id = pthread_self(); std::cout << "I am a new thread: " << threadname << " my id: " << ToHex(id) << std::endl; sleep(1); if(cnt == 5) { // 线程退出,并带上退出信息 pthread_exit((void *)"success"); } cnt++; } } int main() { pthread_t tid; // 创建线程 pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread 1"); // 主线程 // 等待新线程并获取退出信息 void * message = nullptr; int n = pthread_join(tid, &message); std::cout << "Exit information for the new thread: " << (char *)message << ", " << n << std::endl; return 0; }
5. 线程的分离
- 我们创建的新线程默认是joinable的,线程退出之后是需要进行pthread_join()操作的,否则无法释放资源,当我们进行pthread_join()操作时,如果线程不退出,那么就会一直阻塞住,直到线程退出;
- 如果我们不关心线程的返回值,并且在等待线程时也是一种负担,所以这个时候就可以将线程设置为分离状态,即在线程退出的时候,自动释放线程的资源;
- 设置为分离状态的可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离;
- joinable和分离是冲突的,一个线程不能既是joinable又是分离的。
分离指定的线程:
cppint pthread_detach(pthread_t thread);
6. 线程的取消
取消一个执行中的线程:
cppint pthread_cancel(pthread_t thread);
线程如果被分离,是可以进行取消的,但是不能被等待!
朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!