【Linux多线程】认识多线程创建线程

文章目录

  • 什么是多线程
    • 为什么称linux下的线程是轻量级进程呢?
  • 线程的优点
  • 线程的缺点
  • 线程异常
  • 线程和进程
  • 创建线程
    • 1.pthread_create
    • 2.pthread_self

什么是多线程

进程是正在运行的程序的实例,而线程(thread)是进程中的一个执行路线。一个进程可以拥有多个线程。从程序的角度上来说,线程是一个独立运行程序的片段。当程序运行时,进程把大部分资源合理分配给每个执行流(线程),且所有线程共享进程的地址空间,所以线程实际上就是一个轻量级的进程。下面给出进程中的线程示意图:


值得注意的是,windos下的线程是有线程控制块(TCB)的。而linux下的进程控制块和线程控制块都是task_struct

为什么称linux下的线程是轻量级进程呢?

这是因为linux内核并没有单独为线程设计一套管理方案,而是通过相同的机制来管理进程和线程,只不过线程拥有的资源是进程的一部分,所以称linux下的线程是轻量级进程。并且,Linux内核中的调度器并不区分线程和进程,可以是单线程的进程,也可以只是一个线程。为了让用户使用起来区分线程和进程,linux向上(用户态)提供了POSI标准的线程接口(如pthread库),在内核用clone系统调用创建和管理线程。尽管有线程这个模型,但底层还是轻量级的进程

总结:==线程是共享同一进程的地址空间和资源的执行单元=。

线程的优点

  1. 共享资源:同一进程内的线程共享地址空间,能访问相同的全局变量,堆和文件描述符等。这种共享使得线程间通信变得更加高效。
  2. 独立的执行流:每个线程都有自己的程序计数器、寄存器和栈,这使得线程可以独立执行。线程的独立性使得多个线程并行执行多个任务,提高了此程序的响应性和吞吐量。
  3. 轻量级:相比于进程,线程的创建开销会小很多,且不需要分配独立的地址空间。上下文切换也比进程快,因为不涉及地址空间的切换
    4.并发执行:在多核处理器上,不同的线程可以做到真正的并行执行

线程的缺点

  1. 同步复杂性:由于共享进程空间,多个线程同时访问和修改共享数据时可能会导致数据不一致等问题
  2. 性能损失:使用锁和其它同步机制会导致性能下降
  3. 调试难度提高:编写和调试一个多线程程序要比单线程程序困难得多

线程异常

  • 单个线程如果出现除0或者访问野指针等问题导致线程崩溃,进程也会随着崩溃
  • 进程终止,该进程的所有线程都会终止。这也就意味着,如果某一个线程出了异常进而终止进程的话,其它的线程也都会被终止。这也是线程不安全的原因之一。

线程和进程

  • 进程是资源分配的基本单位,而线程是调度的基本单位
  • 具体来说,线程共享以下进程资源:
    • 代码段和数据段
    • 文件描述符表
    • 每种信号的处理方式即handler表
    • 环境变量包括当前工作目录
    • 用户id和组id
  • 虽然线程共享进程的数据,但有属于自己的一些数据:
    • 线程ID
    • 一组寄存器
    • errno错误流
    • 信号屏蔽字
    • 调度优先级

进程和线程的关系如下图:
在这里插入图片描述

创建线程

在linux中,通常使用POSIX线程库,即pthread库。pthread库提供了一组用于线程创建、管理和同步的函数,这些函数被包含在pthread.h头文件中。pthread库的主要包含了线程管理、线程同步、线程属性相关的函数,下面介绍线程管理中的一些常用函数。

1.pthread_create

功能:创建一个新的线程
原型:

#include<pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
  • pthread_t是一个无符号整数
  • thread是指向pthread_t变量的一个指针,用于存储创建线程的标识符ID(输出型参数)
  • pthread_attr_t类型是一个线程属性的类,该类定义了线程的所有属性,包括分离状态、栈的大小等
  • attr是一个指向const pthread_attr_t对象的指针,用于初始化被创建线程的属性。如果设置为NULL,则使用默认属性
  • start_rountine是一个函数指针,该函数的参数和返回值类型都是void*。表示线程线程执行的函数
  • arg是传递给线程函数的参数。可以是NULL,如果需要传递多个参数,可以将其打包成结构体类型对象传进去。同样如果想返回多个值,可以将值打包成一个结构体再返回。
  • 创建成功返回0。失败则返回一个非0值,表示错误代码。常见得到错误码有:
    • EAGAIN:系统资源不足,无法创建更多线程。
    • EINVAL:无效的线程属性
    • EPERM:没有足够的权限设置线程属性

给出代码样例,演示使用pthread_create创建线程:

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>

using namespace std;

void *rout(void *arg)//线程执行函数
{
    while (true)
    {
        cout << "i am thread num: " << *(int *)arg << endl;
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t tid;
    int num = 10;
    int res = pthread_create(&tid, NULL, rout, (void *)(&num));
    if (res != 0)
    {//错误码检查
        fprintf(stderr, "pthread_create: %s\n", strerror(res));
        exit(1);
    }
    while (true)
    {
        cout << "I am main thread" << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
这样我们就成功的使用pthread_create函数创建了一个线程。值得注意的是,执行main函数的线程我们称为主线程。此外,一个线程可以使用pthread_self函数来获取自己的线程ID.

2.pthread_self

功能:获得当前线程的ID
函数原型:

pthread_t pthread_self(void);

于是我们可以将前面的代码样例改一下,观察结果线程ID:

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string.h>

using namespace std;

void *rout(void *arg)
{
    while (true)
    {
        cout << "thread id : " << pthread_self() << " i am thread num: " << *(int *)arg << endl;
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t tid;
    int num = 10;
    int res = pthread_create(&tid, NULL, rout, (void *)(&num));
    if (res != 0)
    {
        fprintf(stderr, "pthread_create: %s\n", strerror(res));
        exit(1);
    }
    while (true)
    {
        cout << "tid: " << tid << "  I am main thread" << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
我i们可以观察到,线程ID是一个非常复杂的数字,这个具体数值通常是由线程库内部实现的,可能会使用内存地址等机制来生成唯一的线程ID。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何顺利通过软考中级系统集成项目管理工程师?

中级资格的软考专业包括"信息系统"&#xff0c;属于软考的中级级别。熟悉软考的人都知道&#xff0c;软考分为初级、中级和高级三个级别&#xff0c;涵盖计算机软件、计算机网络、计算机应用技术、信息系统和信息服务五个专业&#xff0c;共设立了27个资格。本文将详…

GPT-4o:重塑人机交互的未来

一个愿意伫立在巨人肩膀上的农民...... 一、推出 在人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直被视为连接人类与机器的桥梁。近年来&#xff0c;随着深度学习技术的快速发展&#xff0c;NLP领域迎来了前所未有的变革…

Excel快速判断大量身份证性别,VBS代码

身份证判断性别的原理就是,身份证倒数第二位是单数表示是男的,单数是女的 可以用IF公式来判断,但是需要下拉,如果几百上千条数据还好,要是上万就不好拉取了,如果数据太多,可以用VBA代码判断 IF(MOD(VALUE(MID(A1,17,1)),2)0,"女","男") 原理:MID(A1,17,1…

MacBook 怎么玩Windows游戏 苹果笔记本怎么玩游戏?mac上如何玩windows游戏

传统上&#xff0c;Mac 不被认为是好的游戏机。然而&#xff0c;苹果已经开始在 Mac 上的游戏上投入更多精力&#xff0c;特别是自从转向苹果芯片以来。这使得 Mac 游戏的本机移植数量和模拟 Windows 游戏的能力都得到了显著提高。 方法一&#xff1a;Boot Camp 1、Boot Camp是…

正确地安装 Python

Python由荷兰国家数学与计算机科学研究中心的吉多范罗苏姆于1990年代初设计&#xff0c;作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本质&#xff0c;使它成为多数…

windows10远程桌面端口,修改Windows 10远程桌面端口的步骤

在Windows 10操作系统中&#xff0c;远程桌面功能为企业用户、技术支持人员以及个人用户提供了极大的便利&#xff0c;允许他们远程访问和管理另一台计算机的桌面环境。然而&#xff0c;默认的远程桌面端口&#xff08;通常为3389&#xff09;常常成为安全漏洞的潜在目标&#…

粒子辐照环境中相机镜头防护及LabVIEW图像处理注意事项

在粒子辐照环境测试电路板性能的实验中&#xff0c;需要对相机镜头进行有效防护&#xff0c;同时利用LabVIEW进行图像识别和处理。本文将讨论相机镜头防护的关键因素和LabVIEW处理过程中的注意事项&#xff0c;包括防辐射材料选择、辐射屏蔽措施、散热管理、空间布局及LabVIEW软…

Linux驱动开发笔记(二) 基于字符设备驱动的GPIO操作

文章目录 前言一、设备驱动的作用与本质1. 驱动的作用2. 有无操作系统的区别 二、内存管理单元MMU三、相关函数1. ioremap( )2. iounmap( )3. class_create( )4. class_destroy( ) 四、GPIO的基本知识1. GPIO的寄存器进行读写操作流程2. 引脚复用2. 定义GPIO寄存器物理地址 五、…

SC8205LA 20VN沟道增强型MOS(Mos)场效应管

特点 ❥专有的先进平面技术 ❥高密度超低电阻设计 ❥大功率、大电流应用 ❥理想的锂电池应用 ❥封装形式:SOT23-6

总是不能盈利?试着用这两个观点去学习现货白银的技巧

一进入现货白银市场&#xff0c;投资者都想着如何去找到现货白银交易的机会&#xff0c;学习现货白银投资的方法。其实这些都是手段&#xff0c;而最终的目的还是为我们的盈利服务。而对于盈利来说&#xff0c;其实胜率和风险报酬比才是影响盈利的重要因素&#xff0c;我们带着…

Springboot邮件发送配置

Springboot邮件发送配置 pom.xml依赖&#xff1a; <dependency><groupId>org.eclipse.angus</groupId><artifactId>jakarta.mail</artifactId><version>2.0.3</version> </dependency> <dependency><groupId>or…

最简单的安卓模拟器抓包?

安装模拟器抓包似乎是有个绕不开的话题&#xff0c;但是现在普遍的安卓模拟器抓包会遇到以下问题&#xff1a; 1.证书配置繁琐 2.模拟器不兼容软件 3.系统设置繁琐。 前几天写过一次微信小程序如何抓包&#xff0c;现在来讲一下模拟器怎么抓包吧。首先使用的工具还是TangGo测…

Canny算子

Canny算子_百度百科 (baidu.com)https://baike.baidu.com/item/Canny%E7%AE%97%E5%AD%90/8821789?frge_ala 图像处理中最经典的边沿检测算法&#xff1a; Canny边缘检测_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1U4411277i/?spm_id_from333.1007.top_right_bar_…

达梦 结果拼接=多行结果返回一列字符串.

sql 转换 查询出多行数据 (select t.PROPERTY from JD_CODING t left join DELIVERY_OF c on t.VALUE c.TYPE where t.PROPERTY stackingType group by t.PROPERTY) 更改后 转为一列的拼接字符串 ( select listagg( distinct t.PROPERTY,,) within group ( order by t.P…

linux的磁盘分区与管理

磁盘分区与管理 识别磁盘 一块硬盘的“艺术”之旅&#xff08;硬盘空间使用&#xff0c;经历的步骤&#xff09; •识别硬盘 > 分区规划 > 格式化 > 挂载使用 Unix/Linux的基本哲学理念&#xff1a;一切皆文件 /dev:存放设备&#xff08;键盘、鼠标、光驱、硬盘……

AI 绘图要如何入门?有哪些好用的软件推荐?(附工具+教程+变现模式)

1.Ai绘画如何入门 不需要把Ai绘画想的很复杂 抛去复杂的应用 使用现成简单的工具 只需要学会提示词 描述你想要的画面即可 提示词 不需要太复杂&#xff0c;也不能太简单&#xff0c;太简单依赖于ai的基本样式&#xff0c;关键是要抓住你想要的核心描述 AI不太擅长理解人类的…

国产操作系统上部署SVN版本控制系统

原文链接&#xff1a;国产操作系统上部署SVN版本控制系统 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上部署SVN版本控制系统的文章。SVN&#xff08;Subversion&#xff09;是一款广泛使用的版本控制系统&#xff0c;它…

如何正确申请DigiCert OV通配符SSL证书以保护多个子域名?

在网络时代&#xff0c;网站安全性日益受到重视&#xff0c;而HTTPS协议作为保护网站和用户隐私的重要手段&#xff0c;其重要性不言而喻。HTTPS通过加密技术保护数据在传输过程中的安全性&#xff0c;确保网站的可靠性和安全性。然而&#xff0c;许多网站管理员对于如何申请一…

spdlog日志库源码:线程池thread_pool

线程池 线程池本质上一组事先创建的子线程&#xff0c;用于并发完成特定任务的机制&#xff0c;避免运行过程中频繁创建、销毁线程&#xff0c;从而降低程序运行效率。通常&#xff0c;线程池主要涉及到以下几个方面问题&#xff1a; 如何创建线程池&#xff1f;线程池如何执…

Java中的JSON神器,如何轻松玩转复杂数据结构

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、揭秘JSON世界的基石 在Java的世界中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它基于文本&#xff0c;易于阅读和编写&#xff0c;同时也易于…