Linux中的线程(一)-- 线程的创建

2023-11-08

什么是线程?

Linux 中的线程被称为“轻量级进程”(Lightweight Process,LWP),它是在进程内部运行的一种“子进程”。与传统的进程不同,线程共享相同的虚拟地址空间和其他资源,例如打开的文件、信号处理程序和用户 ID 等。

线程具有哪些特点

  1. 轻量级:
    因为线程与父进程共享资源,所以创建和销毁线程的开销要比创建和销毁进程的开销要小得多。
  2. 调度:
    Linux 线程是由内核进行调度的,线程的调度是基于调度策略和优先级来完成的。常见的调度策略包括 Round Robin、FIFO 和实时调度等。
  3. 同步:
    由于线程共享同一进程的地址空间,所以线程之间可以通过共享变量进行通信。Linux 提供了许多同步机制,例如信号量、互斥量和条件变量等,以确保线程之间的同步和互斥。
  4. 线程安全:
    Linux 系统提供了一些线程安全的库和函数,例如 pthread 库,这些库和函数可以在多线程程序中使用,避免竞态条件和其他线程安全问题。
  5. 调试:
    Linux 系统提供了一些工具来调试多线程程序,例如 gdb 调试器和 strace 工具。

线程与进程有什么区别

简单的说,进程是程序资源分配的最小单位,线程是程序执行的最小单位。

  1. 资源共享:
    进程是系统分配资源的基本单位,每个进程都有自己独立的地址空间、文件描述符、信号处理等资源,不同进程之间的资源不共享。而线程则共享同一个进程的地址空间和资源,它们之间可以相互访问共享变量,共享同一进程的文件和打开的网络连接等。
  2. 创建销毁开销:
    创建和销毁进程的开销比创建和销毁线程的开销要大。因为每个进程都有自己独立的地址空间和系统资源,创建一个新的进程需要操作系统分配新的内存空间、建立内核数据结构等,而线程则共享其所属进程的资源,因此创建和销毁线程的开销要比创建和销毁进程的开销要小得多。
  3. 上下文切换:
    线程之间的上下文切换比进程之间的上下文切换要快得多。因为线程共享相同的地址空间和资源,切换时只需要保存和恢复少量的寄存器状态即可,而进程之间的上下文切换需要保存和恢复更多的状态信息,比如虚拟内存空间等。
  4. 并发性和资源竞争
    线程之间的并发性比进程之间的并发性更高,因为它们共享同一进程的地址空间和资源,同时也会导致线程之间发生资源竞争的问题,例如竞争共享变量的访问权等。而进程之间的并发性相对较低,因为它们彼此独立。

如何创建一个线程

Talk is cheap,直接上代码!

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

using namespace std;


void *th_fun(void *arg)
{
    int *p = (int *)arg;
    printf("thread PID = %d\n",getpid());//获取本进程的ID
    printf("thread pthread ID = %d\n",pthread_self());//获取函数自己的ID
    printf("thread PARAMETER = %d\n",*p);//打印传入的参数
}

int main(void)
{
    pthread_t pid;//线程ID
    void *tret;
    int n=10;

    pthread_create(&pid,NULL,th_fun,(void*)&n);//pid 线程ID,传出参数
    pthread_join(pid, &tret);//主线程阻塞等待子线程的终止
    printf("MAIN pthread ID = %x\n",pthread_self());//主控线程的ID号
    printf("MAIN create pthread ID = %x\n",pid);//线程的ID
    printf("MAIN PID = %d\n",getpid());//进程ID

    return 0;
}

解读

主函数通过pthread_create函数创建一个线程,线程的函数名为th_fun,同时有一个pid参数代表线程的ID号,通过pthread_t类型定义。这里在pthread_create最后一个参数中,用了一个n变量负责传入一个数据给线程函数,然后在线程函数中打印出来。
pthread_join负责将线程设置为分离态,负责回收线程的资源。
主函数中分别打印了三个内容,主进程的线程的ID号,创建的新线程的ID号,主进程的ID号。
th_fun内容则简单的多,这个新创建的执行线程只负责打印三个内容:创建本线程的进程ID号,本线程自己的线程ID号,传入的arg参数。

输出

thread PID = 14420
thread pthread ID = 2
thread PARAMETER = 10
MAIN pthread ID = 1
MAIN create pthread ID = 2
MAIN PID = 14420

这里主进程的线程ID号为1,新创建的线程ID为2,该主函数执行时创建的进程ID为14420。
先打印出来thread线程的内容:因为线程是由main函数中创建的,所以进程ID同样为14420。新创建的线程ID和主函数中获取的线程ID一样为2,参数10是通过pthread_create的最后一个参数传进来的,这里要注意最后一个参数的类型为 void* 型,所以在赋值的时候也要将变量转换成 void* 型。

线程原语

实际上和线程有关的函数特别多,通过man命令可以查看到有哪些线程原语:

root@ubuntu:/home# man -k pthread
pthread_attr_destroy (3) - initialize and destroy thread attributes object
pthread_attr_getaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_getdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_getguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_getinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_getschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_getschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_getscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_getstack (3) - set/get stack attributes in thread attributes object
pthread_attr_getstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_getstacksize (3) - set/get stack size attribute in thread attributes object
pthread_attr_init (3) - initialize and destroy thread attributes object
pthread_attr_setaffinity_np (3) - set/get CPU affinity attribute in thread attributes object
pthread_attr_setdetachstate (3) - set/get detach state attribute in thread attributes object
pthread_attr_setguardsize (3) - set/get guard size attribute in thread attributes object
pthread_attr_setinheritsched (3) - set/get inherit-scheduler attribute in thread attributes object
pthread_attr_setschedparam (3) - set/get scheduling parameter attributes in thread attributes object
pthread_attr_setschedpolicy (3) - set/get scheduling policy attribute in thread attributes object
pthread_attr_setscope (3) - set/get contention scope attribute in thread attributes object
pthread_attr_setstack (3) - set/get stack attributes in thread attributes object
pthread_attr_setstackaddr (3) - set/get stack address attribute in thread attributes object
pthread_attr_setstacksize (3) - set/get stack size attribute in thread attributes object
pthread_cancel (3)   - send a cancellation request to a thread
...

由于篇幅限制,后面的一部分就省略掉了,读者可以自行去查看。

那我们这里用到的几个和线程有关的线程原语有:

pthread_create

这个函数负责的是创建线程,通过man命令可以获取如何使用该函数。

#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变量地址进来,用于保存新线程的tid(线程ID)
  • const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL
  • void *(*start_routine) (void *):函数指针,指向新线程应该加载执行的函数模块
  • void *arg:指定线程将要加载调用的那个函数的参数
  • 返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰
  • attr参数表示线程属性,本节不深入讨论线程属性,所有代码例子都传NULL给attr参数,表示线程属性取缺省值,感兴趣的读者可以参考[APUE2e]

pthread_join

调用该函数的线程将挂起等待,直到id为thread的线程终止。也就是在子线程调用了pthread_join()方法后面的代码,只有等到子线程结束了才能执行。

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
  • pthread_t thread:回收线程的tid
  • void **retval:接收退出线程传递出的返回值
  • 返回值:成功返回0,失败返回错误号

注意,这里其实还涉及到与pthread_detach()函数的区别对比。在后续的文章再加以对比说明。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux中的线程(一)-- 线程的创建 的相关文章

  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • 多处理:仅使用物理核心?

    我有一个函数foo它消耗大量内存 我想并行运行多个实例 假设我有一个有 4 个物理核心的 CPU 每个核心有两个逻辑核心 我的系统有足够的内存来容纳 4 个实例foo并行但不是 8 个 此外 由于这 8 个核心中的 4 个是逻辑核心 我也不
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 查找哪个程序运行另一个程序

    我有一个 NAS 运行在 Redhat Linux 的有限版本上 我按照指示破解了它 这样我就可以访问 shell 这很有帮助 我还做了一些修改 其他人也做过修改 除了一个问题之外 它们似乎都工作得很好 不知何故 每隔 22 天 系统就会关
  • 如何使用 GOPATH 的 Samba 服务器位置?

    我正在尝试将 GOPATH 设置为共享网络文件夹 当我进入 export GOPATH smb path to shared folder I get go GOPATH entry is relative must be absolute
  • 是否可以创建一个脚本来保存和恢复权限?

    我正在使用 Linux 系统 需要对一组嵌套文件和目录进行一些权限实验 我想知道是否没有某种方法可以保存文件和目录的权限 而不保存文件本身 换句话说 我想保存权限 编辑一些文件 调整一些权限 然后将权限恢复到目录结构中 将更改的文件保留在适
  • 我不明白 execlp() 在 Linux 中如何工作

    过去两天我一直在试图理解execlp 系统调用 但我还在这里 让我直奔主题 The man pageexeclp 将系统调用声明为int execlp const char file const char arg 与描述 execl exe
  • “make install”将库安装在 /usr/lib 而不是 /usr/lib64

    我正在尝试在 64 位 CentOS 7 2 上构建并安装一个库 为了这个目的我正在跑步 cmake DCMAKE BUILD TYPE Release DCMAKE INSTALL PREFIX usr DCMAKE C COMPILER
  • 如何在基于 Linux 的系统上的 C 程序中使用 mqueue?

    如何在基于 Linux 的系统上的 C 程序中使用 mqueue 消息队列 我正在寻找一些好的代码示例 可以展示如何以正确且正确的方式完成此操作 也许是一个操作指南 下面是一个服务器的简单示例 该服务器接收来自客户端的消息 直到收到告诉其停
  • 使用 Grep 查找两个短语之间的文本块(包括短语)

    是否可以使用 grep 来高亮所有以以下内容开头的文本 mutablePath CGPathCreateMutable 并以以下内容结尾 CGPathAddPath skinMutablePath NULL mutablePath 这两个短
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 确定我可以向文件句柄写入多少内容;将数据从一个 FH 复制到另一个 FH

    如何确定是否可以将给定数量的字节写入文件句柄 实际上是套接字 或者 如何 取消读取 我从其他文件句柄读取的数据 我想要类似的东西 n how much can I write w handle n read r handle buf n a
  • Windows CE 与嵌入式 Linux [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 现在我确信我们都清楚 Linux 与 Windows 桌面的相对优点 然而 我对嵌入式开发世界的了解却少得多 我主要对行业解决方案感兴
  • 在 C++ linux 中将 STRINGS 写入串口

    我知道这个问题遍布互联网 但仍然没有任何东西能让我完全解决这个问题 我想用 C linux 将数据写入 Propeller 板的串行端口 从控制台获取输入时程序运行良好 但是当我向它写入字符串时总是返回 ERROR Invalid comm
  • PyQt5 - 无法使用 QVideoWidget 播放视频

    from PyQt5 QtWidgets import from PyQt5 QtMultimedia import from PyQt5 QtMultimediaWidgets import from PyQt5 QtCore impor
  • 无法在 Perl 中找到 DBI.pm 模块

    我使用的是 CentOS 并且已经安装了 Perl 5 20 并且默认情况下存在 Perl 5 10 我正在使用 Perl 5 20 版本来执行 Perl 代码 我尝试使用 DBI 模块并收到此错误 root localhost perl
  • Linux 上的基准测试程序

    对于一项任务 我们需要使用不同的优化和参数来对我们的实现进行基准测试 有没有一种可行的方法可以在Linux命令行 我知道时间 上使用不同的参数对小程序进行基准测试 从而为我提供CSV或类似内容的时间数据 输出可能类似于 Implementa
  • 如何在 GNU/Linux 上设置 Subversion (SVN) 服务器 - Ubuntu [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一台运行 Ubuntu 的笔记本电脑 我想将其用作 Subversion 服务器 既让我自己在本地承诺 也让其他人远程承诺 要使其
  • 让 TeXstudio 在 linux mint 中工作:找不到文件“url.sty”。

    刚刚切换到 Linux Mint 以前的顽固 Windows 用户 我在尝试安装 TeXstudio 时遇到一些问题 Sudo apt get install texstudio 给了我一个正确的安装 至少 我是这么认为的 但是当我尝试构建

随机推荐

  • python - write() argument must be str, not bytes

    python write argument must be str not bytes 源代码 import requests r requests get https www baidu com img bd logo1 png if r
  • 【满分】【华为OD机试真题2023B卷 JS】计算误码率

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 计算误码率 知识点双指针 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 误码率是最常用的数据通信传输质量指标 它可以理解为 在多少位数据中出现一位差错 移动通信网络中
  • Python进阶语法(一)

    目录 一 Python列表推导式 1 1 使用方法 1 2 列表推导式优点 1 2 1 提升效率 1 2 2 方便转换数据 1 2 3 用于过滤数据 1 3 推广延申 1 3 1 字典推导式 1 3 2 元组推导式 1 3 3 集合推导式
  • Phpstorm好用插件

    IDE Eval Reset 无限次免费刷新30天试用期 插件市场安装 在Settings Preferences gt Plugins 内手动添加第三方插件仓库地址 https plugins zhile io 搜索 IDE Eval R
  • Mybatis 向MySql数据库插入带有日期类型字段的数据

    未验证 我们的实体类里面一个字段的日期类型是util Date 在向数据库插入该实体时会报错 说是 日期哪个字段 Data truncation 所以需要做些更改 在mybatis的MAPPER映射文件中对插入的日期进行相应属性的设置
  • java语言StringUtils工具类

    import com mls util tool codec EncodeUtils import com mls util tool collect ListUtils import org apache commons lang3 St
  • MySQL 故障转移

    在高可用领域 除了通过规范化运维和软硬件优化 提升平均失效时间 MTBF 降低平均恢复时间 MTTR 也非常关键 本文主要讲述的内容是其中的故障转移和故障恢复部分 文章目录 降低平均恢复时间 MTTR 故障探测 I 探测方法 II 探测结果
  • 面试官比较看重简历中的哪些维度,有什么写简历的技巧、建议和总结?

    每日一问 面试官比较看重简历中的哪些维度 有什么写简历的技巧 建议和总结 Datawhale优秀回答者 千夜同学 陶志杰 第一 简历一定要工整 字体格式对奇 字体大小不一 格式错乱 文字乱码的 都懒得看 直接垃圾桶 千万别模版导出 第二 一
  • JS——函数

    文章目录 1 函数 1 1 定义函数 1 2 调用函数 2 变量的作用域 2 1 局部变量 2 2 全局变量 2 3 局部作用域 let 2 4 常量 const 3 方法 1 函数 1 1 定义函数 定义方式一 一旦执行到return代表
  • day6作业

    include
  • 记一次spark streaming+kafka 运行时间不稳定调优历程

    记一次spark streaming kafka 运行时间不稳定调优历程 问题现象 首次使用spark streaming进行流式计算的时候遇到的一个问题 即spark streaming读取kafka消息进行流式计算 但是在数据量比较大的
  • redis查看所有key和value_Redis介绍和数据类型及单机版安装

    Redis 是完全开源免费的 遵守BSD协议 是一个高性能的key value数据库 Redis 与其他 key value 缓存产品有以下三个特点 Redis支持数据的持久化 可以将内存中的数据保存在磁盘中 重启的时候可以再次加载进行使用
  • 36D杯CTF——mengxinstack

    记录一下36D的mengxinstack题目 下载题目 checksec下分析 开启了很多保护 有canary 64位 IDA分析 知道这个程序先执行了一次read 再把read进去的东西print出来 再read 两次read都会造成栈溢
  • (Java)leetcode-1325 Delete Leaves With a Given Value(删除给定值的叶子节点)

    题目描述 给你一棵以 root 为根的二叉树和一个整数 target 请你删除所有值为 target 的 叶子节点 注意 一旦删除值为 target 的叶子节点 它的父节点就可能变成叶子节点 如果新叶子节点的值恰好也是 target 那么这
  • 苹果11文件夹怎么连接服务器,(11)文件服务器

    要求 编写一个 HTTP 文件 服务器 它用于将每次所请求的文件返回给客户端 服务器需要监听所提供的第一个命令行参数所制定的端口 同时 第二个会提供给程序的参数则是所需要响应的文本文件的位置 在这一题中必须使用fs createReadSt
  • 什么是配置环境?如何配置环境?回答很多计算机入门者都会遇到的问题

    什么是配置环境 如何配置环境 回答很多计算机入门者都会遇到的问题 1 前言 编程入门时往往会遇到各种需要配置环境变量的场景 比如刚开始学习python java等 我也和你们一样经历过在网上找各种配环境的教程 然后按部就班地操作 但重复进行
  • 【卡尔曼滤波器】递归算法

    大家好 我是小政 最近在学习卡尔曼滤波 本篇文章记录一下我学习的卡尔曼滤波器中的递归算法 通过举例子让大家更加清晰理解递归到底是什么 希望与同是卡尔曼滤波研究方向的同学进行一些交流 递归算法 1 为什么要用卡尔曼滤波器 2 公式推导 3 举
  • java.lang.OutOfMemoryError: Java heap space .

    java lang OutOfMemoryError Java heap space 解决方案 1 进入eclipse界面中的servers选项卡 右击 工程配置的tomcat项 单击 Open 如图 2 单击 Open launch co
  • c语言课程设计籍贯流程图,学生籍贯信息记录簿(C语言课程设计)教程解读.doc

    计算机科学与技术系 课程设计报告 2012 2013 学年第1学期 课程C语言课程设计课程设计名称学生籍贯信息记录簿设计学生姓名学号专业班级指导教师 目录 一 绪言 需求分析 二 系统设计 一 设计思想 二 源程序设计 三 设计表示 三 系
  • Linux中的线程(一)-- 线程的创建

    什么是线程 Linux 中的线程被称为 轻量级进程 Lightweight Process LWP 它是在进程内部运行的一种 子进程 与传统的进程不同 线程共享相同的虚拟地址空间和其他资源 例如打开的文件 信号处理程序和用户 ID 等 线程