Linux基础知识点-(七-线程)

目录

一、线程和进程

1.1 线程的基本概念

1.2 线程的优缺点

二、创建线程

2.1 pthread_create() - 创建线程函数

三、线程属性

3.1 pthread_attr_t类型

3.2 phread_t类型

四、线程退出

4.1 pthread_exit()

4.2 pthread_join() 

4.3 pthread_detach() 


一、线程和进程

1.1 线程的基本概念

在很多Linux的书籍基本上都是这样子描述进程(process)和线程(thread)的: 进程是资源管理的最小单位,线程是程序执行的最小单位

在操作系统设计上,从进程演化出线程。 线程的出现最主要的目的就是减小进程上下文切换开销,进程是资源管理的最小单位,那么每个进程都拥有自己的数据段、代码段和堆栈段, 这必然就造成了进程间切换时都要进行比较复杂的上下文切换等动作,因为要保存当前进程上下文的内容, 还要恢复另一个进程的上下文。如果是经常切换进程的话,这样子的开销就过于庞大。因为在进程切换上下文时, 需要重新映射虚拟地址空间、进出OS内核、寄存器切换,还会干扰处理器的缓存机制。 因此为了进一步减少CPU在进程切换时的额外开销,Linux进程演化出了另一个概念——线程。

线程是操作系统能够调度和执行的基本单位,在Linux中也被称之为轻量级进程。在Linux系统中, 一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等),而将线程分配到某个CPU上执行。在CPU眼中只认PCB(task_struct),不分进程和线程,进程中的每一个task_struct就是一个线程,他们指向同一个地址空间。

task_struct是进程内部的一个执行流,进程可以重新理解为内部只有一个执行流的进程,多线程可以理解为内部具有多个执行流的进程。 

1.2 线程的优缺点

线程的优点

  • 创建一个新线程的代价要比创建一个新进程小得多
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  • 线程占用的资源要比进程少很多
  • 能充分利用多处理器的可并行数量
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

线程的缺点: 

  • 性能损失
  • 健壮性降低
  • 缺乏访问控制
  • 编程难度提高

线程共享进程数据,但也拥有自己的一部分数据

  •  线程ID
  • 一组寄存器
  • errno
  • 信号屏蔽字
  • 调度优先级

进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符表
  • 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
  • 当前工作目录
  • 用户id和组id

二、创建线程

可移植操作系统接口 (Portable Operating System Interface,缩写为POSIX), POSIX是IEEE为了在各种UNIX操作系统上运行软件而定义API接口等一系列互相关联的标准的总称, 其正式称呼为IEEEStd 1003,而国际标准名称为ISO/IEC9945,此标准源于一个大约开始于1985年的项目。 POSIX这个名称是由理查德·斯托曼(RMS)应IEEE的要求而提议的一个易于记忆的名称。 它基本上是Portable Operating System Interface(可移植操作系统接口)的缩写, 而X则表明其对Unix API的传承。 

在Linux系统下的多线程遵循POSIX标准,而其中的一套常用的线程库是 pthread,它是一套通用的线程库,是由 POSIX提出的,因此具有很好的可移植性,Linux多线程编程也正是使用它,在使用时必须包含以下头文件: 

#include <pthread.h>

除此之外在链接时需要使用库libpthread.a。因为pthread的库不是Linux系统的库, 所以在编译时要加上-lpthread 选项。

2.1 pthread_create() - 创建线程函数

pthread_create()函数是用于创建一个线程的,创建线程实际上就是确定调用该线程函数的入口点, 在线程创建后,就开始运行相关的线程函数。函数原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

参数说明

  • thread:指向线程标识符的指针。

  • attr:设置线程属性,attr为NULL表示默认属性

  • start_routine:start_routine是一个函数指针,指向要运行的线程入口,即线程运行时要执行的函数代码。

  • arg:给start_routine指向的函数传入的参数。

  • 返回值:若线程创建成功,则返回0。若线程创建失败,则返回对应的错误代码。

三、线程属性

3.1 pthread_attr_t类型

 上面pthread_create中需要以线程属性作为输入参数,在Linux中线程属性结构如下:

typedef struct
{int                   etachstate;      //线程的分离状态int                   schedpolicy;     //线程调度策略structsched_param     schedparam;      //线程的调度参数int                   inheritsched;    //线程的继承性int                   scope;           //线程的作用域size_t                guardsize;       //线程栈末尾的警戒缓冲区大小int                   stackaddr_set;   //线程的栈设置void*                 stackaddr;       //线程栈的位置size_t                stacksize;       //线程栈的大小
}pthread_attr_t;

线程的属性非常多,而且其属性值不能直接设置,须使用相关函数进行操作。线程属性主要包括如下属性: 作用域(scope)、栈大小(stacksize)、栈地址(stackaddress)、优先级(priority)、 分离的状态(detachedstate)、调度策略和参数(scheduling policy and parameters)。 默认的属性为非绑定、非分离、1M的堆栈大小、与父进程同样级别的优先级,无其他特别需求,是可以不需要考虑线程相关属性的,使用默认的属性即可。

3.2 phread_t类型

pthread_ create函数会产生一个线程ID,存放在第一个参数thread中,该参数指向一个虚拟地址空间中共享区的某块区域,该区域用于管理线程的栈结构,且主线程使用的为内核提供的栈结构,子线程使用的是该区域提供的栈结构(一个多线程中包含一个主线程和多个子线程),以此来实现线程之间栈相对独立,该区域的起始地址即为新创建线程的线程ID,线程库NPTL提供了pthread_ self()函数,该函数的返回值为线程自身的ID。

pthread_t pthread_self(void);

四、线程退出

4.1 pthread_exit()

在线程创建后,系统就开始运行相关的线程函数,在该函数运行完之后,该线程也就退出了, 这是线程的一种隐式退出的方法,这与进程的退出差不多,进程完成工作后就会退出。 而另一种退出线程的方法是使用pthread_exit()函数,让线程显式退出,这是线程的主动行为。 这里要注意的是,在使用线程函数时,不能随意使用exit()退出函数来进行出错处理, 这是因为exit()函数的作用是使调用进程终止,而一个进程往往包含多个线程,因此,在使用exit()之后,该进程中的所有线程都会被退出,因此在线程中只能调用线程退出函数pthread_exit()而不是调用进程退出函数exit(),pthread_exit()函数原型如下:

void pthread_exit(void *retval);

参数说明

  • retval:如果retval不为空,则会将线程的退出值保存到retval中,如果不关心线程的退出值,形参为NULL即可。

4.2 pthread_join() 

一般情况下,进程中各个线程的运行是相互独立的,线程的终止并不会相互通知,也不会影响其他的线程, 终止的线程所占用的资源不会随着线程的终止而归还系统,而是仍为线程所在的进程持有,这是因为一个进程中的多个线程是共享数据段的。进程之间可以使用wait()系统调用来等待其他进程结束,线程也有类似的函数:

int pthread_join(pthread_t thread, void **rval_ptr);

如果某个线程想要等待另一个线程退出,并且获取它的退出值,那么就可以使pthread_join()函数完成,以阻塞的方式等待tid指定的线程结束,当函数返回时,被等待线程的资源将被收回,如果进程已经结束,那么该函数会立即返回。并且tid指定的线程必须是可结合状态的,该函数执行成功返回0,否则返回对应的错误代码。

参数说明

  • thread: 线程标识符,即线程ID,标识唯一线程。

  • rval_ptr: 用户定义的指针,用来存储被等待线程的返回值。

需要注意的是一个可结合状态的线程所占用的内存仅当有线程对其执行立pthread_join()后才会释放,因此为了避免内存泄漏,所有线程的终止时,要么已被设为detached,要么使用pthread_join()来回收资源。

4.3 pthread_detach() 

默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。如果不关心线程的返回值,join是一种负担,这个时候,可以通过pthread_detach()函数将线程设置为detached,当线程退出时,自动释放线程资源,pthread_detach()函数如下:

int pthread_detach(pthread_t thread);

 参数说明

  • thread: 线程标识符,即线程ID,标识唯一线程。

  • 返回值:成功返回0,失败返回-1

joinable和detached是冲突的,一个线程不能既是joinable又是detached,可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:pthread_detach(pthread_self())。

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>/*要执行的线程*/
void *test_thread(void *arg)
{int num = (int)arg; printf("This is test thread, arg is %d\n", num);sleep(5);/*退出线程*/pthread_exit(NULL);
}int main(void)
{pthread_t tid;void *thread_return;int arg = 520;int res;printf("start create thread\n");/*创建线程,线程执行test_thread函数*/res = pthread_create(&tid, NULL, test_thread, (void*)(arg));if(res != 0){printf("create thread fail\n");exit(res);}printf("create treads success\n");printf("waiting for threads to finish...\n");/*等待线程终止*/res = pthread_join(tid, &thread_return);if(res != 0){printf("thread exit fail\n");exit(res);}printf("thread exit ok\n");return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/605902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019数据结构----单链表真题

思路&#xff1a; (1)找到中间节点,将原链表一分为二 (2)后半段链表原地逆置 (3)合并链表 #include <stdio.h> #include <stdlib.h>//定义节点类型 typedef struct LNode {int data;//数据域struct LNode *next;//指针域 } LNode, *LinkList;void tailList(Link…

Rational rose 安装和使用 教程

前言 win10和win11都可以用&#xff0c;亲测了win10 Unified Modeling Language (UML)又称统─建模语言或标准建模语言&#xff0c;是始于1997年一个OMG标准&#xff0c;它是一个支持模型化和软件系统开发的图形化语言&#xff0c;为软件开发的所有阶段提供模型化和可视化支持…

Spark---RDD算子(单值类型转换算子)

文章目录 1.RDD算子介绍2.转换算子2.1 Value类型2.1.1 map2.1.2 mapPartitions2.1.3 mapPartitionsWithIndex2.1.4 flatMap2.1.5 glom2.1.6 groupBy2.1.7 filter2.1.8 sample2.1.9 distinct2.1.10 coalesce2.1.11 repartition2.1.12 sortBy 1.RDD算子介绍 RDD算子是用于对RDD进…

15K star! 搭建个人PDF工具箱,和广告、泄密说拜拜

我相信很多人都曾经遇到过这样的麻烦&#xff1a;一大堆PDF文档摆在面前要处理&#xff0c;拆分、标页码、调顺序、加签名。手忙脚乱的在网上找了几个工具&#xff0c;但是要么需要付费&#xff0c;要么各种广告还不好用&#xff0c;更容易出现隐私泄露的问题。 今天我们推荐的…

轨迹合并 合并轨迹

搜索微信小程序 merge gpx

测试电脑的公网ip

发现ip地址总是变化&#xff0c;想要了解变化规律 操作 反复关闭打开浏览器&#xff0c;查询ip地址&#xff0c;共查询了15次。出现了5种不同的地址&#xff0c;还好&#xff0c;不是无穷的。

python 各级目录文件读取

目录结构 import pytestdef test_01():# 同级文件with open(1.txt, r, encodingutf-8) as file:content file.read()print(content)def test_02():# 同级目录的下的文件with open(rupfile/2.txt, r, encodingutf-8) as file:content file.read()print(content)def test_03():…

IDEA[Debug]简单说明

目录 &#x1f95e;1.打断点 &#x1f32d;2.第一组按钮 &#x1f9c2;3.第二组按钮 &#x1f953;4.参数查看 1.打断点 1.在需要断点处打上断点&#xff0c;然后点击debug运行 2.执行debug&#xff0c;直接执行到断点处 2.第一组按钮 共有8按钮&#xff0c;从左往右依…

Linux实验——页面置换算法模拟

页面置换算法模拟 【实验目的】 &#xff08;1&#xff09;理解虚拟内存管理的原理和技术。 &#xff08;2&#xff09;掌握请求分页存储管理的思想。 &#xff08;3&#xff09;理解常用页面置换算法的思想。 【实验原理/实验基础知识】 存储器是计算机系统的重要资源之…

可怜的小猪

题目 有 buckets 桶液体&#xff0c;其中 正好有一桶 含有毒药&#xff0c;其余装的都是水。它们从外观看起来都一样。为了弄清楚哪只水桶含有毒药&#xff0c;你可以喂一些猪喝&#xff0c;通过观察猪是否会死进行判断。不幸的是&#xff0c;你只有 minutesToTest 分钟时间来…

msvcp140.dll丢失的解决方法,从两个方向解决msvcp140.dll丢失

在Windows操作系统上&#xff0c;msvcp140.dll是Visual C Redistributable for Visual Studio 2015的一部分&#xff0c;如果msvcp140.dll文件丢失&#xff0c;可能在尝试启动使用C运行时库的程序时遇到错误&#xff0c;应用程序可能也会相应的无法打开&#xff0c;那么有什么m…

Qt/C++摄像头采集/二维码解析/同时采集多路/图片传输/分辨率帧率可调/自动重连

一、前言 本地摄像头的采集可以有多种方式&#xff0c;一般本地摄像头会通过USB的方式连接&#xff0c;在嵌入式上可能大部分是CMOS之类的软带的接口&#xff0c;这些都统称本地摄像头&#xff0c;和网络摄像头最大区别就是一个是通过网络来通信&#xff0c;一个是直接本地通信…

浅谈顺序表基本操作

&#x1f937;‍♀️&#x1f937;‍♀️&#x1f937;‍♀️ 今天给大家带来的是数据结构——顺序表的实现(增删查改)。 清风的CSDN博客主页 &#x1f389;欢迎&#x1f44d;点赞✍评论❤️收藏 &#x1f61b;&#x1f61b;&#x1f61b;希望我的文章能对你有所帮助&#xff…

JavaWeb基础(2)- Web概述、HTTP协议、Servlet、Request与Response

JavaWeb基础&#xff08;2&#xff09;- Web概述、HTTP协议、Servlet、Request与Response 文章目录 JavaWeb基础&#xff08;2&#xff09;- Web概述、HTTP协议、Servlet、Request与Response3 Web概述3.1 Web和JavaWeb的概念3.2 JavaWeb技术栈3.2.1 B/S架构**3.2.2 静态资源**3…

不带控制器打包exe,转pdf文件时失败的原因

加了注释的两条代码后&#xff0c;控制器会显示一个docx转pdf的进度条。这个进度条需要控制器的实现&#xff0c;如果转exe不带控制器的话&#xff0c;当点击转换为pdf的按钮就会导致程序出错和闪退。 __init__.py文件的入口

Netplan介绍

1 介绍 1.1 简介 Netplan是一个抽象网络配置描述器。通过netplan命令&#xff0c;你只需用一个 YAML文件描述每个网络接口所需配置。netplan并不关系底层管理工具是NetworkManager还是networkd。 它是一个在 Linux 系统上进行网络配置的实用程序。您创建所需接口的描述并定义…

java: 5-3 for

文章目录 1. for1.1 基本语法1.2 练习1.3 执行流程1.4 细节1.5 编程思想 (练习) 1. for 1.1 基本语法 for 关键字&#xff0c;表示循环控制for 有四要素: (1)循环变量初始化(2)循环条件(3)循环操作(4)循环变量迭代循环操作 , 这里可以有多条语句&#xff0c;也就是我们要循环…

FreeRTOS学习第6篇–任务状态挂起恢复删除等操作

目录 FreeRTOS学习第6篇--任务状态挂起恢复删除等操作任务的状态设计实验IRReceiver_Task任务相关代码片段实验现象本文中使用的测试工程 FreeRTOS学习第6篇–任务状态挂起恢复删除等操作 本文目标&#xff1a;学习与使用FreeRTOS中的几项操作&#xff0c;有挂起恢复删除等操作…

在MeshLab中创建简单的几何对象

文章目录 立方体和平面网格正多面体圆形相关球类隐式曲面 在Filters->Create New Mesh Layer的子菜单中&#xff0c;提供了大量几何对象&#xff0c;列表如下 菜单指令图形菜单指令图形Dodecahedron正十二面体Icosahedron正二十面体Tetrahedron正四面体Octahedron正八面体B…

Kafka(五)生产者

目录 Kafka生产者1 配置生产者bootstrap.serverskey.serializervalue.serializerclient.id""acksallbuffer.memory33554432(32MB)compression.typenonebatch.size16384(16KB)max.in.flight.requests.per.connection5max.request.size1048576(1MB)receive.buffer.byte…