当前位置: 首页 > news >正文

【Linux】线程控制

一、POSIX线程库

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_"开头的
  • 要使用这些函数库,要通过引入头文件<pthread.h>
  • 连接这些线程函数库时要使用编译器命令的“-lpthread”选项

二、线程的一些函数

2.1 创建线程——pthread_create函数

2.1.1 函数介绍

函数的原型:

函数的功能:

       创建一个新的线程

函数的参数:

  • thread:输出型参数,返回线程的ID
  • attr:设置线程的属性,一般我们使用默认属性,将attr设为NULL
  • start_routine:是一个函数地址,线程启动后要执行的函数
  • arg:传给线程启动函数的参数

函数的返回值:

  • 成功返回0
  • 失败返回错误码 

2.1.2 错误检查

  • 传统的一些函数是:成功返回0,失败返回-1,并且对全局变量errno赋值用来指示错误
  • pthreads函数出错时不会设置全局变量errno(而大部分的其他POSIX函数会这样做),而是将错误码通过返回值返回
  • pthreads同样也提供了线程内的errno变量,以支持其他使用errno的代码,对于pthreads函数的错误,建议通过返回值来判定,因为读取返回值要比读取线程内的errno变量的开销更小

2.1.3 举例代码

#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>// 新线程
void* threadStart(void* arg)
{while (true){std::cout << "thread-new running..." << "pid: " << getpid() << std::endl;sleep(1);}
}int main()
{pthread_t tid;//            线程的ID 设置属性   线程要执行的函数  执行函数的参数pthread_create(&tid, nullptr, threadStart, (void*)"thread-new");// 主线程while (true){sleep(1);std::cout << "main thread running..." << "pid: " << getpid() <<std::endl;}return 0;
}

2.1.4 一些细节

问题一:新线程和老线程谁先运行?

       不确定,因为在计算机中,线程的调度是不确定的。

问题二:我们期望这个线程谁最后退出?

       我们希望主线程最后退出,因为主线程还要等待其他线程,进行回收。

问题三:如何看待线程函数传参?

       我们可以向该参数传递任何类型的数据,包括类对象的地址,但要记得该对象的成员...

2.1.5 如何创建多个线程?

#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <unistd.h>
#include <vector>void* threadrun(void* args)
{std::string name = static_cast<const char*>(args);while (true){std::cout << name << "is running" << std::endl;sleep(1);}
}int main()
{std::vector<pthread_t> pthreads;for(int i = 0; i < 10; i++){pthread_t tid;// 线程的名字char* name = (char*)malloc(sizeof(int) * 128);snprintf(name, sizeof name, "thread-%d", i + 1);int n = pthread_create(&tid, nullptr, threadrun, name);//sleep(1);pthreads.push_back(tid); // 将创建出来的线程id存储在pthreads数组中}return 0;
}

2.2 线程等待函数——pthread_join函数

2.2.1 函数介绍

函数的原型:

函数的功能:

       主线程等待新线程的pid,等待线程的结束,如果我们不进行等待线程,那么会照成线程的内存泄漏,但是要注意没有“僵尸线程”的概念

函数的参数:

  • thread:线程ID
  • value_ptr:指向一个指针,后者指向线程的返回值

函数的返回值:

  • 成功返回0
  • 失败返回错误码 

2.2.2 函数的第二个参数

       调用该函数的线程将挂起等待,直到ID为thread的线程终止。thread线程以不同的方式终止,通过pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值
  2. 如果thread线程被别的线程调用pthread_cancel异常终止,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED
  3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数
  4. 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数

如何全面看待线程的返回? 

       线程的返回值只有正确的返回值,当线程出现异常后,直接全部崩溃,没有错误返回的机会,所以,线程在退出的时候,我们只需要考虑结果对不对,一个线程只要写崩溃,其他线程也会崩溃

       我们也可以传递任意类型

2.2.3 线程访问的变量最好在堆空间中

       在一个主函数中,如果线程需要访问的数据是在主函数的栈空间的,那么我们需要谨慎。如果说,只有一个线程还好,但是如果有两个及其以上的线程需要访问的话,会有一定的错误发生。因为一个线程将其值进行修改,会影响到另一个线程,所以我们需要进行malloc变量,然后使进程访问在堆开辟的空间交给对应的线程,每一个线程人手一个堆空间,不会进行相互影响。

2.3 线程ID以及进程地址空间布局——pthread_self函数

2.3.1 函数介绍

函数的原型:

函数的功能:

       我们可以使用这个函数返回指定线程的线程ID

函数的返回值:        

       线程ID

2.3.2 介绍一下线程id 

  • pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中,LWP和线程ID不是已回事情
  • LWP属于进程调度的范畴,因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一表示该线程
  • pthread_create函数的第一个参数指向一个虚拟地址空间,该内存单元即为新创建的线程的线程ID,属于NPTL线程库的范畴,线程库的后续操作,就是根据该线程ID来操作线程的
  • 线程库NPTL提供了pthread_self函数,可以获得线程自身的ID

2.3.3 来简要介绍一下pthread_t类型

       这种类型取决于实现,对于LInux目前实现的NPTL实现而言,pthread_t 类型的线程ID,本质上是一个进程地址空间上的一个地址。 

2.3 线程终止

2.3.1 终止线程的三种方法

如果需要只终止某个线程而不终止整个进程,可以有三个方法:

  • 从线程函数中return,这种方法对主线程不适用,从main函数中调用return相当于调用exit
  • 线程可以调用pthread_exit进行终止自己
  • 一个线程可以调用pthread_cancel终止同一个进程的另一个线程

2.3.2 pthread_exit函数

函数的原型:

函数的功能:

       线程终止

函数的参数:

       value_str:value_str不要指向一个局部变量,和return的变量是一样的

       需要注意:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配的。因为当其他线程达到这个返回指针时,线程函数已经退出了。

2.3.3 pthread_cancel函数

函数的原型:

函数的功能:

       取消一个执行中的线程

函数的参数:

  • thread:线程ID

函数的返回值:

  • 成功返回0
  • 失败返回错误码

2.4 分类线程

2.4.1 可不可以不join线程,让线程执行完就自动退出?可以!!!!!

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
  • 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
  • 如果一个线程被分离,线程的工作状态属于分离状态,不需要也不能被join的

2.4.2 函数介绍 

函数的原型:

函数的功能:

       线程的分离

函数的参数:

       thread:线程的ID

三、C++11多线程

在C++中不使用Linux这一套,代码如下:要记得加pthread库,否则会报错!!!!!!!

#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <thread>
#include <string>
#include <cstring>
#include <unistd.h>
#include <vector>void threadrun(int num)
{while (num){std::cout << "thread - 1" << " is running" << std::endl;num--;sleep(1);}
}int main()
{std::thread mythread(threadrun, 10);while (true){std::cout << "main thread is running" << std::endl;sleep(1);}mythread.join();return 0;
}

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

相关文章:

  • MongoDB CRUD操作:地理位置查询
  • 操作系统教材第6版——个人笔记6
  • WPF国际化的最佳实践
  • SASS模块化与组织文件
  • 5-Maven-setttings和pom.xml常用配置一览
  • c#vb代码互转工具
  • SpringBoot+Vue校园管理系统(前后端分离)
  • MySQL分页:ROW_NUMBER() vs LIMIT
  • 【JMeter接口测试工具】第一节.JMeter简介和安装【入门篇】
  • vue 文件预览mp4、txt、pptx、xls、xlsx、docx、pdf、html、xml
  • SAP Build引言
  • AI绘画工具
  • 暑期来临,AI智能视频分析方案筑牢防溺水安全屏障
  • Linux `free` 命令:深入解析系统内存使用情况**
  • C语言 | Leetcode C语言题解之第136题只出现一次的数字
  • 时间复杂度分析经典问题——最大子序列和
  • Java 网络编程(2):UDP 的使用
  • Java超时控制的实现
  • jquery cookie
  • MySQL数据库运维之数据恢复
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • Node 版本管理
  • PHP CLI应用的调试原理
  • Python_OOP
  • web标准化(下)
  • 百度地图API标注+时间轴组件
  • 缓存与缓冲
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 七牛云假注销小指南
  • 前端工程化(Gulp、Webpack)-webpack
  • 如何实现 font-size 的响应式
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 1.Ext JS 建立web开发工程
  • kubernetes资源对象--ingress
  • (1)svelte 教程:hello world
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (BFS)hdoj2377-Bus Pass
  • (ZT)薛涌:谈贫说富
  • (二)pulsar安装在独立的docker中,python测试
  • (二十四)Flask之flask-session组件
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • .bat批处理(一):@echo off
  • .Net IE10 _doPostBack 未定义
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .net 按比例显示图片的缩略图
  • .net 无限分类
  • .NET 依赖注入和配置系统
  • .NET 直连SAP HANA数据库
  • .NET轻量级ORM组件Dapper葵花宝典
  • .考试倒计时43天!来提分啦!
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [100天算法】-不同路径 III(day 73)