[C++/Linux] Linux线程详解

目录

 

一.什么是线程?

并发(Concurrency)

并行(Parallelism)

  1.1 线程的概念

  1.2 线程的基本函数

 1.3 线程的基本使用例子:

 二.线程的属性

2.1线程属性使用例子

三.线程互斥

 3.1互斥锁

3.2互斥锁常用函数 

 3.3互斥锁使用例子


一.什么是线程?

    在Linux中,线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。同一进程中的多条线程将共享该进程所拥有的全部资源,但每条线程都有各自的调用栈和程序计数器,能够独立运行。

   那么什么是并发与并行呢?        

并发(Concurrency)

并发是指系统能够处理多个同时发生的任务。在并发编程中,多个任务在同一时间段内执行,但它们可能不是同时执行。并发可以通过时间分片(time slicing)来实现,操作系统快速地在多个任务之间切换,给人一种同时执行的错觉。

并发的主要目的是提高资源的利用率和系统的响应速度。例如,在一个Web服务器中,可以同时处理多个用户的请求,这样就可以更有效地利用服务器的资源,并缩短用户的等待时间。

并行(Parallelism)

并行是指系统能够在同一时刻执行多个任务。并行编程需要多个处理器或者多个核心,每个处理器或核心可以独立地执行一个任务。并行是真正的“同时”执行,它通过增加计算资源来提高性能。

并行的主要目的是通过同时执行多个任务来提高性能和缩短任务的完成时间。例如,在一个多核处理器上,可以同时运行多个线程或者进程,这样可以显著减少执行复杂计算或者数据处理任务所需的时间。

  1.1 线程的概念

  • 轻量级进程(Lightweight Process, LWP):线程又被称为轻量级进程,因为线程的创建、撤销和切换比进程更快。
  • 线程的属性:线程具有就绪、阻塞和运行三种基本状态,以及创建和终止两种辅助状态。
  • 线程的执行:线程可以并发执行,这意味着它们似乎是在同时运行,但实际上是在CPU时间片轮转机制下快速切换执行。

如何使用线程:

在Linux中,线程可以通过 POSIX 线程(pthread)库来使用。这个库提供了一系列函数来创建、同步和管理线程。

线程共享资源

1.文件描述符表
2.每种信号的处理方式
3.当前工作目录
4.用户ID和组ID
5.内存地址空间 (.text/.data/.bss/heap/共享库)


线程非共享资源

1.线程id
2.处理器现场和栈指针(内核栈)
3.独立的栈空间(用户空间栈)
4.errno变量
5.信号屏蔽字
6.调度优先级

线程优、缺点

  • 优点: 1. 提高程序并发性 2. 开销小 3. 数据通信、共享数据方便
  • 缺点: 1. 库函数,不稳定 2. 调试、编写困难、gdb不支持 3. 对信号支持不好
  • 优点相对突出,缺点均不是硬伤。Linux下由于实现方法导致进程、线程差别不是很大

  1.2 线程的基本函数

基本函数介绍和使用:

  1. 线程创建:pthread_create

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    
    • thread:指向线程标识符的指针。
    • attr:线程属性,通常设为NULL表示使用默认属性。
    • start_routine:线程运行函数的起始地址。
    • arg:运行函数的参数。
  2. 线程终止:pthread_exit

    void pthread_exit(void *retval);
    
    • retval:线程的返回值。
  3. 等待线程终止:pthread_join

    int pthread_join(pthread_t thread, void **retval);
    
    • thread:等待终止的线程标识符。
    • retval:存储线程返回值的指针。
  4. 线程取消:pthread_cancel

    int pthread_cancel(pthread_t thread);
    
    • thread:要取消的线程标识符。
  5. 线程互斥锁:pthread_mutex_lock/unlock

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    
    • mutex:互斥锁变量,用于同步线程对共享资源的访问。

 1.3 线程的基本使用例子:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 线程运行函数
void *print_message_function(void *ptr) {char *message;message = (char *) ptr;printf("%s \n", message);return NULL;
}int main() {pthread_t thread1, thread2;char *message1 = "Thread 1";char *message2 = "Thread 2";// 创建线程1if(pthread_create(&thread1, NULL, print_message_function, (void*) message1)) {printf("Error creating thread 1\n");return 1;}// 创建线程2if(pthread_create(&thread2, NULL, print_message_function, (void*) message2)) {printf("Error creating thread 2\n");return 1;}// 等待线程终止if(pthread_join(thread1, NULL)) {printf("Error joining thread 1\n");return 2;}if(pthread_join(thread2, NULL)) {printf("Error joining thread 2\n");return 2;}return 0;
}

在这个例子中:

  • 定义了一个print_message_function函数,它接收一个指向字符数组的指针,并打印出来。
  • main函数中,创建了两个线程thread1thread2,它们都执行print_message_function函数,但分别传递了不同的消息。
  • 使用pthread_create创建线程,使用pthread_join等待线程结束。

程序执行时,会创建两个线程,它们可能会并发地运行,打印出各自的消息。使用pthread_join确保了主程序会等待这两个线程完成它们的任务后再退出。

 二.线程的属性

线程属性(Thread Attributes)是可以用来定制线程的各种特性的集合。在创建线程时,可以指定线程的属性,如果不指定,线程会使用默认属性。线程属性通过pthread_attr_t结构体来表示,并且在使用前需要初始化。

常见的线程属性包括:

  • detachstate:线程的分离状态属性,可以设置为PTHREAD_CREATE_JOINABLE(默认值,可以调用pthread_join来等待线程结束)或PTHREAD_CREATE_DETACHED(线程一旦结束,其资源立即被回收,不能被等待)。
  • schedpolicy:线程的调度策略,可以是SCHED_OTHER(默认值,普通轮转调度),SCHED_FIFO(先来先服务调度),或SCHED_RR(时间片轮转调度)。
  • inheritsched:线程的继承调度策略,可以设置为PTHREAD_EXPLICIT_SCHED(显式指定线程的调度属性)或PTHREAD_INHERIT_SCHED(继承创建它的线程的调度属性,默认值)。
  • scope:线程的作用域,可以设置为PTHREAD_SCOPE_SYSTEM(与系统范围内的线程竞争CPU时间)或PTHREAD_SCOPE_PROCESS(仅与同一进程内的线程竞争CPU时间,通常是默认值)。

2.1线程属性使用例子

#include <pthread.h>int main() {pthread_attr_t attr;pthread_attr_init(&attr); // 初始化线程属性// 设置线程为分离状态pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);// 使用线程属性创建线程pthread_t thread;pthread_create(&thread, &attr, thread_function, NULL);// 清理线程属性pthread_attr_destroy(&attr);// ... 其他代码 ...return 0;
}

三.线程互斥

 3.1互斥锁

互斥锁(Mutex):

互斥锁是一种同步机制,用于防止多个线程同时访问共享资源。在多线程环境中,当多个线程尝试同时访问同一资源时,互斥锁确保任何时刻只有一个线程能够访问该资源。

3.2互斥锁常用函数 

常用的互斥锁函数:

  • 初始化互斥锁:pthread_mutex_init

    c

    复制

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    
    • mutex:指向互斥锁变量的指针。
    • attr:互斥锁属性,通常设为NULL表示使用默认属性。
  • 锁定互斥锁:pthread_mutex_lock

    c

    复制

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    
    • mutex:指向互斥锁变量的指针。
  • 尝试锁定互斥锁:pthread_mutex_trylock

    c

    复制

    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    
    • mutex:指向互斥锁变量的指针。如果互斥锁已经被锁定,函数不会阻塞,而是返回错误码。
  • 解锁互斥锁:pthread_mutex_unlock

    c

    复制

    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    
    • mutex:指向互斥锁变量的指针。
  • 销毁互斥锁:pthread_mutex_destroy

    c

    复制

    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    
    • mutex:指向互斥锁变量的指针。

 3.3互斥锁使用例子

#include <pthread.h>// 全局变量
pthread_mutex_t lock; // 互斥锁
int shared_data = 0; // 共享数据// 线程函数
void *thread_function(void *arg) {pthread_mutex_lock(&lock); // 加锁shared_data++; // 访问共享数据pthread_mutex_unlock(&lock); // 解锁return NULL;
}int main() {pthread_mutex_init(&lock, NULL); // 初始化互斥锁pthread_t threads[10];for(int i = 0; i < 10; i++) {pthread_create(&threads[i], NULL, thread_function, NULL); // 创建线程}for(int i = 0; i < 10; i++) {pthread_join(threads[i], NULL); // 等待线程结束}pthread_mutex_destroy(&lock); // 销毁互斥锁printf("Shared data: %d\n", shared_data); // 输出共享数据的最终值return 0;
}

在这个例子中,我们创建了一个互斥锁lock来保护对shared_data的访问。每个线程在访问shared_data之前都会尝试锁定互斥锁,完成访问后解锁。这样可以确保在任一时刻只有一个。

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

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

相关文章

GeoServer:忘记密码重置

操作步骤 1. 找到data_dir/security/usergroup/default目录下的users.xml文件&#xff0c; 2.修改password为plain:geoserver&#xff0c; 这里无论原来的密码是什么&#xff0c;改为plain:geoserver之后&#xff0c;就可以通过admin&#xff1a;geoserver默认账户密码登录了。…

[计算机效率] 鼠标手势工具:WGestures(解放键盘的超级效率工具)

3.22 鼠标手势工具&#xff1a;WGestures 通过设置各种鼠标手势和操作进行绑定。当用户通过鼠标绘制出特定的鼠标手势后就会触发已经设置好的操作。有点像浏览器中的鼠标手势&#xff0c;通过鼠标手势操纵浏览器做一些特定的动作。这是一款强大的鼠标手势工具&#xff0c;可以…

2024年能源环境、材料科学与人工智能国际会议(ICEEMSAI2024)

2024年能源环境、材料科学与人工智能国际会议(ICEEMSAI2024) 会议简介 2024国际能源环境、材料科学和人工智能大会&#xff08;ICEEMSAI 2024&#xff09;主要围绕能源环境、物质科学和人工智慧等研究领域&#xff0c;旨在吸引能源环境、先进材料和人工智能专家学者、科技人员…

C++入门语法(命名空间缺省函数函数重载引用内联函数nullptr)

目录 前言 1. 什么是C 2. C关键字 3. 命名空间 3.1 命名空间的定义 3.2 命名空间的使用 4. C输入和输出 5. 缺省函数 5.1 概念 5.2 缺省参数分类 6. 函数重载 6.1 概念 6.2 为何C支持函数重载 7. 引用 7.1 概念 7.2 特性 7.3 常引用 7.4 引用与指针的区别 7…

最近一些前端面试问题整理

最近一些前端面试问题整理 4月8号1. TS 中的 类型别名 和接口的区别是什么&#xff1f;2. 什么是深拷贝和浅拷贝&#xff1f;深浅拷贝的方法有哪些&#xff1f;浅拷贝&#xff08;Shallow Copy&#xff09;深拷贝&#xff08;Deep Copy&#xff09;区别总结 3. 使用 JSON.strin…

Python中Python-docx 包的run介绍

先对run做一个简单地介绍。每个paragraph对象都包含一个run对象的列表。举例&#xff1a; 这是一个简短的段落。 from docx import Document doc Document("1.docx") #上面这段话保存在1.docx中 print("这一段的run个数是&#xff1a;",len(doc.paragr…

GitHub repository - Code - Issues - Pull Requests - Wiki

GitHub repository - Code - Issues - Pull Requests - Wiki 1. Code2. Issues3. Pull Requests4. WikiReferences 1. Code 显示该仓库中的文件列表。仓库名下方是该仓库的简单说明和 URL. 2. Issues 用于 BUG 报告、功能添加、方向性讨论等&#xff0c;将这些以 Issue 形式进…

ESXI 中安装 虚拟机 麒麟v10 操作系统

浏览器访问登录ESXI 上传镜像文件 创建新虚拟机 选择虚拟机名称和操作系统 选择存储 配置虚拟机 配置虚拟机 cpu 内存 硬盘 并选择虚拟机驱动 配置完成后&#xff0c;点击下一步&#xff0c;并点击完成。 开机 完成后选择该虚拟机&#xff0c;并打开电源 等待出现以下界面…

[Linux_IMX6ULL驱动开发]-驱动的分层及实现

目录 驱动分层的思路 驱动分层的实现 上层驱动的实现 次设备号的使用 上层驱动代码 底层驱动的实现 底层驱动c文件的实现 底层驱动头文件实现 应用层文件的实现 驱动分层的思路 在上一篇文章中&#xff0c;博主实现了通过寄存器控制引脚&#xff0c;以此来达到控制LE…

代码随想录-KMP算法

LeetCode28: . - 力扣&#xff08;LeetCode&#xff09; public class KMP {public static void main(String[] args) {KMP kmpnew KMP();kmp.strStr("aabaabaaf","aabaaf");}public int strStr(String haystack, String needle) {//获取next数组int[] nex…

ENVI实战—一文搞定NDVI计算和MNDWI计算

实验1&#xff1a;使用波段计算器计算波段值 目的&#xff1a;熟练掌握ENVI中波段计算器的使用方法&#xff0c;学会波段之间的运算。 过程&#xff1a; ①数据导入&#xff1a;打开ENVI5.6&#xff0c;在“文件”选项卡中选择“打开”&#xff0c;打开此前裁剪好的Sentinel…

外包干了3天,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;19年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

✔ ★Java项目——设计一个消息队列(二)

Java项目——设计一个消息队列 四. 项⽬创建五. 创建核⼼类创建 Exchange&#xff08;名字、类型、持久化&#xff09;创建 MSGQueue&#xff08;名字、持久化、独占标识&#xff09;创建 Binding&#xff08;交换机名字、队列名字、bindingKey用于与routingKey匹配&#xff09…

【经典算法】LeetCode25:K 个一组翻转链表(Java/C/Python3,Hard)

#算法 目录 题目描述思路及实现方式一&#xff1a;递归思路代码实现Java 版本C 语言版本Python3 版本 复杂度分析 方式二&#xff1a;迭代和原地反转思路代码实现Java 版本C 语言版本Python3 版本 复杂度分析 总结相似题目 标签&#xff1a;链表、递归 题目描述 给你链表的头…

代码随想录阅读笔记-二叉树【总结】

二叉树的理论基础 代码随想录 (programmercarl.com)&#xff1a;二叉树的种类、存储方式、遍历方式、定义方式 二叉树的遍历方式 深度优先遍历 代码随想录阅读笔记-二叉树【递归遍历】-CSDN博客&#xff1a;递归三部曲初次亮相代码随想录阅读笔记-二叉树【迭代遍历】-CSDN博…

2024年3月文章一览

2024年3月编程人总共更新了12篇文章&#xff1a; 1.2024年2月文章一览 2.Programming Abstractions in C阅读笔记&#xff1a;p308-p311 3.Programming Abstractions in C阅读笔记&#xff1a;p312-p326 4.Programming Abstractions in C阅读笔记&#xff1a;p327-p330 5.…

基于SSM的电影网站(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电影网站&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMv…

Ollama教程——兼容OpenAI API:高效利用兼容OpenAI的API进行AI项目开发

相关文章: Ollama教程——入门&#xff1a;开启本地大型语言模型开发之旅 Ollama教程——模型&#xff1a;如何将模型高效导入到ollama框架 Ollama教程——兼容OpenAI API&#xff1a;高效利用兼容OpenAI的API进行AI项目开发 Ollama教程——兼容OpenAI API&#xff1a;高效利用…

L2-2 巴音布鲁克永远的土(二分+并查集)

思路&#xff1a;我们可以二分答案&#xff0c;然后判断当前答案合不合理。 对于判断答案合理&#xff0c;可以用并查集&#xff0c;看mid能否把所有检查点连进一个集合中&#xff0c;枚举每个结点&#xff0c;如何当前结点周围的四个方向可以连的话&#xff0c;就加进同一个集…

【电子通识】热风枪的结构与使用方法

热风枪的结构 热风枪是专门用来拆焊、焊接贴片元器件和贴片集成电路的焊接工具&#xff0c;它主要由主机和热风焊枪两大部分构成。 热风枪主要有电源开关、风速设置、温度设置、热风连接等部件组成。根据不同品牌和价位的热风枪&#xff0c;有一些功能齐全的也集成了烙铁功能。…