Linux系统编程系列之线程

news2024/10/5 23:35:55

一、什么是线程

        线程(Thread)是计算机中的基本执行单元,是操作系统调度的最小单位。线程是进程内的一个独立执行流程,一个进程可以包含多个线程,这些线程共享进程的资源,但每个线程都有自己的独立栈空间以及程序计数器。

二、线程与进程的优缺点

        1、线程的优点

        (1)、线程创建和销毁的开销比进程小,因为线程共享进程中的地址空间和其他资源。

        (2)、线程可以同时执行多个任务,提高了系统的并发性能。

        (3)、线程之间的通信和同步比进程之间的通信和同步更快捷和简单,因为线程共享同一进程的内存。

        (4)、线程可用于执行GUI等交互性任务而不会卡住整个应用程序。

        2、线程的缺点

        (1)、 多线程访问共享数据时,需要使用同步技术,否则会导致不可预期的结果。

        (2)、 线程的调试和bug定位比较困难,因为多个线程共享进程的执行环境。

        (3)、 如果线程中出现了异常,可能会影响整个进程。

        3、进程的优点

        (1)、 进程相互独立,不会相互影响,因此更加健壮和安全。

        (2)、进程可以在不同的硬件和操作系统上运行,更具有可移植性。

        (3)、 进程使用管道等IPC(进程间通信)机制可以方便的实现进程之间的通信和同步。

        4、进程的缺点

        (1)、进程创建和销毁的开销比较大,因为每个进程都需要独立的地址空间和系统资源。

        (2)、进程之间通信和同步需要使用IPC技术,比较繁琐和复杂。

        (3)、进程的并发性能比较差,不能同时执行多个任务。

三、线程的使用场景

        1、多任务处理:多线程可以同时处理多个任务,提高程序的执行效率和响应速度。

        2、并发访问:当多个线程同时访问共享资源时,需要使用线程控制技术,避免出现竞态条件和死锁等问题。

        3、异步编程:线程可以在后台执行一些耗时的操作,不会阻塞主线程,提高程序的用户体验。

        4、服务器编程:服务器一般要同时处理多个客户端请求,使用多线程可以提高服务器的并发处理能力。

        5、图形界面编程:图形界面程序中需要使用线程避免阻塞用户界面,实现异步更新UI界面。

        6、大数据处理:对于大数据处理和分析,多线程可以提高数据处理的效率和速度。

        7、游戏开发:游戏开发中需要实时更新游戏画面和处理用户输入,需要使用多线程技术实现。

四、与线程有关的函数API

        1、线程的创建

        创建一条POSIX线程非常简单,只需要指定线程的执行函数即可

// 创建一条线程
int pthread_create(pthread_t *thread, 
                   const pthread_attr_t *attr,
                   void *(*start_routine) (void *), 
                   void *arg);

// 接口说明:
    返回值:成功返回0,失败返回一个错误码
    参数thread:新线程的TID
    参数attr:线程属性,若创建标准线程则该参数可设置为NULL
    参数start_routine:线程函数,是一个回调函数,跟信号的例程函数有点像
    参数arg:线程函数的参数

         2、线程的退出

        与进程类似,当一条线程执行完毕其任务时,可以使用接口来退出

// 线程的退出
void pthread_exit(void *retval);

// 接口说明
    参数retval:线程的返回值,若线程没有数据可返回则可写成NULL

pthread_exit()与exit()的区别
pthread_exit():退出当前线程
exit():退出当前进程(即退出进程中的所有进程)

         3、线程的结合

        与进程类似,线程退出后不会立即释放其所占有的系统资源,而会成为一个僵尸线程。其他线程可使用pthread_join()来释放僵尸线程的资源,并可获得其退出时返回的退出值,该函数接口被称为线程的接合函数:

// 阻塞等待指定线程退出
int pthread_join(pthread_t tid, void **val);

// 非阻塞接合指定线程退出
int pthread_tryjoin_np(pthread_t tid, void **retval);

// 在指定时间内阻塞接合指定线程的退出
int pthread_timedjoin_np(pthread_t tid, void **retval, const struct timespec *ashtime);

// 接口说明
    (1)若指定tid的线程尚未退出,那么该函数将持续阻塞
    (2)若只想阻塞等待指定线程tid退出,而不想要其退出值,那么val可置为NULL
    (3)若指定tid的线程处于分离状态,或者不存在,则该函数会出错返回

        4、获取线程TID

        

// 获取线程TID
pthread_t pthread_self(void);

// 接口说明
    返回值:线程TID

该接口类似进程管理中的getpid(),但是进程的PID是系统全局资源,而线程的TID仅限于进程内部的线程间有效。当我们要对某条线程执行发送信号,取消,阻塞接合等操作时,需要用到线程的TID。

        5、线程错误码

        线程函数对系统错误码的处理跟标准C库函数的处理方式有很大不同,标准C库函数会对全局错误码errno进行设置,而线程函数发生错误时会直接返回错误码。以线程接合为例,若要判定接合是否成功,成功的情况下输出僵尸线程的退出值,失败的情况下输出失败的原因,实现代码应该这么写

#include <error.h> // 头文件中定义了errno变量

void *val;

errno = pthread_join(tid, &val);

if(errno == 0)
{
    printf("成功接合线程,其退出值为:%d\n", (int)val;
}
else
{
    perror("接合线程失败");
}

        6、函数单例

        许多时候,我们希望某个函数只被严格执行一次,这种需求在一些初始化功能模块中尤为常见,但是如果某个进程中内含多条线程,无法预先知晓哪条线程会先执行,那么初始化就会被执行多次,但如果使用函数单例就会只执行一次。

// 函数单例启动接口
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));

// 接口说明
    
    参数once_control:用来关联某个函数单例,被关联的函数单例只会被执行一遍
    参数init_routine:函数指针指向的函数就是只执行一遍的函数单例

// 通常参数once_control指定为函数单例控制
    pthread_once_t once_control = PTHREAD_ONCE_INIT;

五、案例

// 线程的案例

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>

int flag = 0;   // 简单的标志位来控制同步
char data[100];

// 线程1的例程函数,用来接收数据
void *recv_routine(void *arg)
{
    printf("I am recv_routine, my tid = %ld\n", pthread_self());
    while(1)
    {
        if(flag)
        {
            printf("pthread1 read data: %s\n", data);
            memset(data, 0, sizeof(data));
            flag = 0;
        }
    }
}

// 线程2的例程函数,用来发送数据
void *send_routine(void *arg)
{
    printf("I am send_routine, my tid = %ld\n", pthread_self());
    while(1)
    {
        printf("please input data:\n");
        fgets(data, 100, stdin);
        printf("pthread2 send data\n");
        flag = 1;
    }
}

int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;

    // 创建线程1,用来接收数据
    errno = pthread_create(&tid1, NULL, recv_routine, NULL);
    if(errno == 0)
    {
        printf("pthread create recv_routine success, tid = %ld\n", tid1);
    }
    else
    {
        perror("pthread create recv_routine fail\n");
    }

    // 创建线程2,用来发送数据
    errno = pthread_create(&tid2, NULL, send_routine, NULL);
    if(errno == 0)
    {
        printf("pthread create send_routine success, tid = %ld\n", tid2);
    }
    else
    {
        perror("pthread create send_routine fail\n");
    }

    // 一定要加这个,否则主函数直接退出,相当于进程退出,所有线程也退出
    // 或者加上while(1)等让主函数不退出
    pthread_exit(0);
    
    return 0;
}

六、总结

        线程可以提供系统的并发性,开销比进程更加小,但是不如进程健壮,移植性好。线程有自己的属性,下一篇博客将讲解。

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

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

相关文章

基于SSM的学生事务处理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

matplotlib从起点出发(9)_Tutorial_9_cycler

0 需求 绘图时有时需要指定几种颜色&#xff0c;或者线型&#xff0c;我们统称为样式&#xff0c;让绘制出的内容在这些样式中循环配置。这时就需要使用到本文所提到的技巧&#xff0c;即cycler. 1 进入教程 本文是自定义属性循环(cycler)设置的演示&#xff0c;用于控制多线…

travel总结:

1、前期准备&#xff1a; 对于项目的大体构成做了一定的了解&#xff0c;然后主要是做后端的数据处理&#xff0c;前期的准备的话创建项目的大体结构&#xff0c;servlet、service、domain、dao、utils的项目结构。以及一些基础的代码的生成&#xff0c;我觉得最主要的是一些基…

leetCode 55.跳跃游戏 贪心算法

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入…

MySQL的卸载与安装(Linux)

MySQL 前言1. 卸载MySQL1.1 查询与关闭对应MySQL服务1.2 卸载对应安装包 2. 安装MySQL2.1 配置MySQL官方yum源2.2 开始安装MySQL 前言 在这里演示的卸载与安装MySQL都是在Linux的Centos 7.6 环境下&#xff0c;不同环境会有所出入。 为了避免安装和卸载MySQL过程中受到权限的…

CF505B Mr. Kitayuta‘s Colorful Graph

Mr. Kitayuta’s Colorful Graph 题面翻译 给出一个 n n n 个点&#xff0c; m m m 条边的无向图&#xff0c;每条边上是有颜色的。有 q q q 组询问 对于第 i i i 组询问&#xff0c;给出点对 u i , v i u_i,v_i ui​,vi​。求有多少种颜色 c c c 满足&#xff1a;有至…

算法-动态规划/trie树-单词拆分

算法-动态规划/trie树-单词拆分 1 题目概述 1.1 题目出处 https://leetcode.cn/problems/word-break/description/?envTypestudy-plan-v2&envIdtop-interview-150 1.2 题目描述 2 动态规划 2.1 解题思路 dp[i]表示[0, i)字符串可否构建那么dp[i]可构建的条件是&…

基于ssm的互联网废品回收/基于web的废品资源利用系统

摘 要 本毕业设计的内容是设计并且实现一个基于SSM框架的互联网废品回收。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&#xff0c;Tomcat网络信息服务作为应用服务器。互联网废品回收的功能已基本实现&#xff0c;主要包括用户、回收员、物品分类、回收物品、用户下单…

W、X、Y

W z学长的apex 不等于180度的角的个数就是求转折点的个数 而每个y(x)都是一元函数&#xff0c;按照公式每个一元函数的转折点为 s(x)是若干y(x)的叠加&#xff0c;其中一个y(x)有转折点&#xff0c;在对应位置上s(x)也会有转折点 所以所有y(x)函数中不重复的转折点的个数就是…

Java练习题-键盘录入字符串实现大小写转换

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java练习题 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又…

【LeetCode热题100】--108.将有序数组转换为二叉搜索树

108.将有序数组转换为二叉搜索树 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 二叉搜索树的中序遍历是升序…

扩容LVM卷导致lvm元数据丢失的恢复过程

一、问题描述 因某次MySQL binlog占用过高扩容时&#xff0c;是直接对云盘操作&#xff0c;而扩容直接操作了lvm卷而未操作云盘分区&#xff0c;并随后执行了扩容的partprobe&#xff0c;resize2fs卷等操作&#xff1b;最后&#xff0c;显示并未扩容成功&#xff0c;重启系统后…

008:连续跌三天,买第四天上涨的盈利计算

尽管有连续三天跌&#xff0c;第四天上涨的概率>0.5&#xff0c;但是也不意味着一定会盈利。因为还要看涨跌大幅度。所以&#xff0c;我们应该来假设&#xff0c;于连续跌三天的最后时刻买入&#xff0c;而后第四天临近收盘卖出&#xff0c;看这样的最终盈利是多少。假设我们…

网络-SSE

文章目录 前言一、SSE简介1、SSE特点Polyfill 2、SSE原理3、SSE技术实现&#xff1a;4、SSE应用场景&#xff1a;5、EventSource 二、SSE使用1、前端2、后端3、完整代码前端后端 总结 前言 本文主要记录SSE通讯的简介、使用、以及原理和一个ChatGPT返回数据的demo。 一、SSE简…

专业图像处理软件DxO PhotoLab 7 mac中文特点和功能

DxO PhotoLab 7 mac是一款专业的图像处理软件&#xff0c;它为摄影师和摄影爱好者提供了强大而全面的照片处理和编辑功能。 DxO PhotoLab 7 mac软件特点和功能 强大的RAW和JPEG格式处理能力&#xff1a;DxO PhotoLab 7可以处理来自各种相机的RAW格式图像&#xff0c;包括佳能、…

Redis中Hash类的操作

Redis中Hash类型是键值对的形式保存数据&#xff0c;其中键被称为字段&#xff08;field&#xff09;&#xff0c;值称为字段值&#xff08;value&#xff09;。在一个key中&#xff0c;字段不能重复&#xff0c;而值可以重复。无论是字段还是值都是无序的&#xff08;保存的次…

React封装自定义表单校验方法

一、表单校验 为什么要封装自定义表单校验方法&#xff0c;因为在后台管理系统中&#xff0c;通常我们会涉及到用户的添加或则信息的修改&#xff0c;这时候通常就涉及表单的相关校验。但通常一个系统中的表单校验针对同一个字段来说是统一的。因此我们就需要将对应的校验字段的…

【LeetCode热题100】--98.验证二叉搜索树

98.验证二叉搜索树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 由于二…

41 二叉树的层序遍历

二叉树的层序遍历 题解1 迭代——BFS题解2 递归——DFS 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 提示&#xff1a; 树中节点数目在范围 [0, 2000] 内-1000 < Node.val <…

实时目标检测:基于YOLOv3和OpenCV的摄像头应用

一、前言 随着人工智能和计算机视觉技术的不断发展,目标检测成为了智能监控、自动驾驶、机器人等领域的关键技术之一。实时目标检测更是对系统的反应速度和准确度提出了更高的要求。本文介绍使用OpenCV和YOLOv3实现实时目标检测的方法,演示如何使用OpenCV调用YOLOv3模型进行…