【Linux系统编程】第四十三弹---多线程编程指南:线程终止方式与C++11中的thread

news/2025/3/31 22:22:48/

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、线程终止

1.1、pthread_exit() 

1.2、pthread_cancel() 

1.3、pthread_detach() 

2、C++11中thread 


1、线程终止

问题7 : 新线程如何终止?

1、线程函数 return 

2、pthread_exit 

3、main thread call pthread_cancel ,新线程退出结果是-1 

上一弹已经演示了使用函数return终止进程的方式,此处就只介绍后两种方式了!

可不可以使用我们前面学习过的exit函数终止线程呢?

答案是不能,exit是专门用来终止进程的!

const int num = 10;void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);while (true){std::cout << name << " is running" << std::endl;sleep(1);break; // 1秒后退出循环}exit(1); // 进程: 专门用来终止进程的,不能终止线程
}// main函数结束: main thread 结束,表示进程结束!
int main()
{std::vector<pthread_t> tids;for (int i = 0; i < num; i++){// 1.有线程的idpthread_t tid;// 2.有线程的名字(正确示范)char* name  = new char[128];snprintf(name, 128, "thread-%d", i + 1);pthread_create(&tid, nullptr, threadrun, /*线程的名字*/ name);// 3.保存所有线程的id信息tids.emplace_back(tid);}for(auto tid : tids){void* name = nullptr;pthread_join(tid,&name);std::cout << (const char*)name << " quit" << std::endl;delete (const char*)name;}// 主线程不退sleep(100);return 0;
}

1.1、pthread_exit() 

pthread_exit()

pthread_exit - 退出一个线程#include <pthread.h>void pthread_exit(void *retval);

参数:

  • retval:这是一个指向返回值的指针,该返回值可以被其他线程通过 pthread_join 函数获取。如果线程不需要返回任何值,可以将此参数设置为 nullptr。

代码演示

修改上面新线程函数代码即可!

void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);while (true){std::cout << name << " is running" << std::endl;sleep(1);break; // 1秒后退出循环}pthread_exit(args); // 专门终止一个线程的!
}

运行结果 

1.2、pthread_cancel() 

 方式三:pthread_cancel

pthread_cancel()

pthread_cancel - 向指定的线程发送取消请求#include <pthread.h>int pthread_cancel(pthread_t thread);

参数

  • thread:指定需要取消的目标线程的标识符。

返回值

  • 成功时返回 0
  • 失败时返回非零值,并设置相应的错误码。

代码演示

const int num = 10;void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);// 死循环while (true){std::cout << name << " is running" << std::endl;sleep(1);}pthread_exit(args); // 专门终止一个线程的!
}// main函数结束: main thread 结束,表示进程结束!
int main()
{std::vector<pthread_t> tids;for (int i = 0; i < num; i++){// 1.有线程的idpthread_t tid;// 2.有线程的名字(正确示范)char* name  = new char[128];snprintf(name, 128, "thread-%d", i + 1);pthread_create(&tid, nullptr, threadrun, /*线程的名字*/ name);// 3.保存所有线程的id信息tids.emplace_back(tid);}sleep(3);// join todofor(auto tid : tids){pthread_cancel(tid); // 取消新线程std::cout << "cancel: " << PrintToHex(tid) << std::endl;void* result = nullptr; // 线程被取消线程的退出结果是:-1 #define PTHREAD_CANCELED ((void *) -1)pthread_join(tid,&result);std::cout << (long long int)result << " quit" << std::endl;}// 主线程不退sleep(100);return 0;
}

 运行结果 

问题8: 可不可以不join线程,让它执行完就退出呢?

可以!detach分离

a. 一个线程被创建,默认是joinable的,必须要被join的.

b. 如果一个线程被分离,线程的工作状态分离状态,不需要/不能被join的. 依旧属于进程内部,但是不需要被等待了

1.3、pthread_detach() 

pthread_detach - 将指定的线程设置为分离状态#include <pthread.h>int pthread_detach(pthread_t thread);

参数

  • thread:指定要设置为分离状态的线程的标识符。

返回值

  • 成功时返回 0
  • 失败时返回非零值,并设置相应的错误码。
pthread_self - 获取当前线程的线程标识符#include <pthread.h>pthread_t pthread_self(void);

返回值

pthread_self 函数返回一个 pthread_t 类型的值,该值表示调用线程的线程标识符。这个标识符是一个不透明的数据类型,通常用于在线程管理、线程间通信和同步等操作中标识当前线程。

不分离线程且终止线程

代码演示

const int num = 10;void *threadrun(void *args)
{// pthread_detach(pthread_self());std::string name = static_cast<const char *>(args);while (true){std::cout << name << " is running" << std::endl;sleep(1);break; // 1秒后退出循环}pthread_exit(args); 
}int main()
{std::vector<pthread_t> tids;for (int i = 0; i < num; i++){pthread_t tid;char* name  = new char[128];snprintf(name, 128, "thread-%d", i + 1);pthread_create(&tid, nullptr, threadrun, /*线程的名字*/ name);tids.emplace_back(tid);}// join todofor(auto tid : tids){void* name = nullptr;int n = pthread_join(tid,&name);std::cout << (const char*)name << " quit...,n: " << n << std::endl;delete (const char*)name;}// 主线程不退sleep(100);return 0;
}

运行结果  

新线程分离自己

代码演示

const int num = 10;void *threadrun(void *args)
{pthread_detach(pthread_self());std::string name = static_cast<const char *>(args);while (true){std::cout << name << " is running" << std::endl;sleep(1);break; }pthread_exit(args); 
}int main()
{std::vector<pthread_t> tids;for (int i = 0; i < num; i++){pthread_t tid;char* name  = new char[128];snprintf(name, 128, "thread-%d", i + 1);pthread_create(&tid, nullptr, threadrun, /*线程的名字*/ name);tids.emplace_back(tid);}// sleep(1);// join todofor(auto tid : tids){void* result = nullptr;int n = pthread_join(tid,&result);std::cout << (long long int)result << " quit...,n: " << n << std::endl;}// 主线程不退//sleep(100);return 0;
}

运行结果  

主线程分离新线程

代码演示

void *threadrun(void *args)
{std::string name = static_cast<const char *>(args);while (true){std::cout << name << " is running" << std::endl;sleep(1);break; }pthread_exit(args); 
}int main()
{std::vector<pthread_t> tids;for (int i = 0; i < num; i++){pthread_t tid;char* name  = new char[128];snprintf(name, 128, "thread-%d", i + 1);pthread_create(&tid, nullptr, threadrun, /*线程的名字*/ name);tids.emplace_back(tid);}for(auto tid : tids){pthread_detach(tid);// 主线程分离新线程,前提新线程需要存在}// 分离后无需joinfor(auto tid : tids){void* result = nullptr;int n = pthread_join(tid,&result);std::cout << (long long int)result << " quit...,n: " << n << std::endl;}return 0;
}

 运行结果 

2、C++11中thread 

C++11多线程的本质就是对原生线程库接口的封装。

代码演示 

void threadrun(std::string name,int num)
{while(num){std::cout << name << " num : " << num<< std::endl;num--;sleep(1);}
}int main()
{std::string name = "thread-1";std::thread mythread(threadrun,name,10); // 创建线程while(true){std::cout << "main thhread..." << std::endl;sleep(1);}mythread.join(); // 终止线程return 0;
}

运行结果  


http://www.ppmy.cn/news/1545366.html

相关文章

ubuntu编译内核安装启动

下载源码 apt update apt install linux-source # /usr/src/linux-source-5.4.0/linux-source-5.4.0.tar.bz2 下载源码 tar -jxvf linux-source-5.4.0.tar.bz2 # /usr/src/linux-source-5.4.0 解压源码 安装依赖 sudo apt -y install build-essential sudo apt -y i…

SQL,力扣题目571, 给定数字的频率查询中位数

一、力扣链接 LeetCode_571 二、题目描述 Numbers 表&#xff1a; ------------------- | Column Name | Type | ------------------- | num | int | | frequency | int | ------------------- num 是这张表的主键(具有唯一值的列)。 这张表的每一行表示某个数…

SpringBoot框架的企业资产管理自动化

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了企业资产管理系统的开发全过程。通过分析企业资产管理系统方面的不足&#xff0c;创建了一个计算机管理企业资产管理系统的方案。文章介绍了企业资产管理系统的系…

规范:项目、目录、文件、样式、事件、变量、方法、url参数、注释、git提交 命名规范及考证

一、规范命名的重要性 易懂、通用、规范、标准、专业性、是经验积累的体现 1.1、常见命名方法 序号命名方法解释1全小写2全大写3驼峰&#xff1a;小驼峰命名法4驼峰&#xff1a;大驼峰命名法5烤串命名法 / 脊柱命名法6下划线分隔法 二、项目名 采用小写字母和中划线&#…

GitHub | 发布到GitHub仓库并联文件夹的方式

推送到Github 推送步骤如果你只想更新单个文件&#xff0c;只需在第 4 步中指定该文件的路径即可。可能问题一 效果 推送步骤 更新 GitHub 仓库中的文件通常涉及以下步骤&#xff1a; 克隆仓库&#xff1a; 首先&#xff0c;你需要将 GitHub 上的仓库克隆到本地。使用 git …

在OceanBase 中,实现自增列的4种方法

本文作者&#xff1a;杨敬博&#xff0c;爱可生 DBA 团队成员。 背景描述 在OceanBase数据库中&#xff0c;存在MySQL租户与Oracle租户两种模式&#xff0c;本文主要讲解在 OceanBase 的Oracle模式&#xff08;以下简称OB Oracle&#xff09;&#xff0c;创建自增列的4种方式&…

【SQL实验】高级查询(难点.三)含附加数据库操作

完整代码在文章末尾【代码是自己的解答&#xff0c;并非标准答案&#xff0c;也有可能写错&#xff0c;文中可能会有不准确或待完善之处&#xff0c;恳请各位读者不吝批评指正&#xff0c;共同促进学习交流】 将素材中的“学生管理”数据库附加到SQL SERVER中&#xff0c;完成以…

Huffman(哈夫曼)编码(贪心)(笔记)

最优编码问题&#xff1a; 给出n个字符的频率ci&#xff0c;给每个字符赋予一个01编码串&#xff0c;使得任意一个字符的编码不是另一个字符的前缀&#xff08;这个称为前缀码&#xff09;&#xff0c;而且编码后的总长度&#xff08;每个字符的频率与编码长度乘积的总和&…