简 述: 上一篇讲解了多线程的入门的知识,如何创建多线程程序,以及从虚拟地址空间和 PCB 分析线程的一些细节。本章再讲述一些线程操作相关的函数:
- pthread_exit(): 退出一个线程,不会影响其他线程的
- pthread_jion(): 阻塞等待线程退出,获取线程退出的状态
- pthread_detach(): 设置线程分离的属性
- pthread_cancel(): 杀死(取消)一个线程
- pthread_equal(): 判断两个线程是否相等,预留函数
[TOC]
本文初发于 “偕臧的小站“,同步转载于此。
编程环境:
💻: uos20
📎 gcc/g++ 8.3
📎 gdb8.0
💻: MacOS 10.14
📎 gcc/g++ 9.2
📎 gdb8.3
单个线程退出 pthread_exit():
- 作用: 一个进程的退出使用
exit(0)
; 而退出一个线程,使用pthread_exit(NULL)
;
void pthread_exit(void *value_ptr);
参数:
- value_ptr:必须指向全局,或者堆。是一个传出参数,用来在该线程结束推出的时候,传输一个内容。若是指向局部变量,该线程被销毁了的话,其他线程可能访问不到此块数据块。
写一个例子:
#include <stdio.h> #include <unistd.h> #include <pthread.h> int num = 13; //设置为全局变量,在全局区域,共享 void* myfun(void* arg); int main(int argc, char *argv[]) { void* p = (void *)# //传一个地址进去(voi* 也是 4 个字节) pthread_t id[5] = {0}; for (int i = 0; i < 5; i++) { pthread_create(&(id[i]), NULL, myfun, p); printf("i = %d, thread id: %ld\n", i, id[i]); } // pthread_exit(nullptr); //终止主线程 int j = 0; while (true) { sleep(1); printf ("main thread-----%d------\n", j++); } return 0; } void* myfun(void* arg) { for (int i = 0; i < 5; i++) { printf ("child thread-----%d------\n", i); if (i == 2) { _exit(0); //退出进程 // pthread_exit(nullptr); //终止主线程 } } return nullptr; }
运行结果:
阻塞等待退出线程退出 pthread_jion():
作用:
阻塞等待线程退出,获取线程退出的状态
int pthread_join(pthread_t thread, void **value_ptr);
参数:
- thread: 要回收的子线程的 id
- value_ptr:读取线程退出时候的携带信息状态;指向的内存和 pthread_exit 的参数是指向同一块内存地址 。在上一个函数 pthread_exit(void *value_ptr) 中,线程退出的时候,传出来了全局变量的指针; 而这里第二个参数,此二级指针就可以读出来这个值。
写了一例子:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <pthread.h> int number = 1234; //要是一个全局的变量哦,或者是堆的空间 void* myfun(void* arg); int main(int argc, char *argv[]) { pthread_t pthread = 0; int ret = pthread_create(&pthread, NULL, myfun, NULL); if (ret != 0) printf("error: %s\n", strerror(ret)); printf("parent thread id: %ld\n", pthread_self); void* ptr = nullptr; pthread_join(pthread, &ptr); //阻塞等待子线程退出,并且回收 pcb printf("number = %d\n", *((int*)ptr)); int i = 0; while (i < 10 ) { printf("parent i = %d\n", i++); } return 0; } void* myfun(void* arg) { printf("child thread id: %ld\n", pthread_self()); for (int i = 0; i < 5; i++) { if (i == 2) { // int number = 1234; //若是为栈里面的数据,则会组线程里面,会崩溃或者失败 pthread_exit(&number); //此处的地址,必须是指向堆或者全局变量 } printf("child i = %d\n", i); } return NULL; }
运行效果:
线程分离 pthread_detach():
在用 pthread_create 创建子线程的时候,第三个参数,是可以设置为此属性的;正常情况下,是由子线程死亡,是由父线程来释放遗留的资源;但如果设置了此线程分离的属性,那么子线程是在创建的时候,就独立于父线程,其死亡时候资源也是由自己来释放。
int pthread_detach(pthread_t thread);
- 调用该函数之后,就不在需要调用 pthread_jion() 了
杀死(取消)线程 pthread_cancel():
int pthread_cancel(pthread_t thread);
- 注意:
- 要杀死子线程对应的处理的函数的内部,必须做一次系统调用。
- 系统调用函数有,eg: open,write, printf 等,这次都是最终会调用到系统层及的函数。
- 不涉及到系统层级调用,eg: int a = 10;
判断线程是否相等 pthread_equal():
是一个预留函数 ,通过线程号 判断两个线程是否相等;目前不需要使用该函数。若是以后线程变为返回一个结构体。就可以用此预留函数(修改一下实现)来判断两个线程是否实现了。
int pthread_equal(pthread_t t1, pthread_t t2);
下载地址:
欢迎 star 和 fork 这个系列的 linux 学习,附学习由浅入深的目录。