Linux应用开发笔记(五)网络编程(二)多线程编程

文章目录

  • 前言
  • 一、线程和进程
    • 1. 进程(Process)
    • 2. 线程(Thread)
    • 3. 二者的比较
  • 二、多线程和多进程
  • 三. 代码编写
    • 1. 相关函数
      • pthread_create( )函数
      • pthread_exit( )函数
      • pthread_join( )函数
    • 2. 线程同步
    • 3. 互斥量
    • 4. 条件变量
    • 5. 实验代码


前言

  在前面的学习中,我们提到了ROTS操作系统的特点,即可以多线程操作命令,这样的好处是可以同时操作好几个目标,而不是因为上一个目标未结束使得需要的操作陷入阻塞状态。

一、线程和进程

  这是一个常用的术语,通常情况下线程和进程是指操作系统中用于实现并发执行的两个基本单位,它们各自具有不同的特点和适用场景。

1. 进程(Process)

  定义:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位。它包含了一个程序的当前执行状态,包括程序计数器、内存指针以及多个寄存器的当前值等。
  资源占用:每个进程都拥有独立的内存空间和系统资源,如代码、数据、堆栈等。
  独立性:进程之间是相互独立的,一个进程的崩溃不会影响到其他进程。
  通信与同步:进程间的通信(IPC)通常通过管道、消息队列、共享内存等方式实现,而同步则需要使用信号量、互斥锁等机制。
  开销:由于进程拥有独立的资源,因此创建、销毁和切换进程的开销相对较大。

2. 线程(Thread)

  定义:线程是进程内的一条执行路径或执行流,是系统调度的基本单位。线程共享进程的资源,包括代码、数据、打开的文件、信号处理器和进程ID等。
  资源占用:线程之间共享进程的内存空间和系统资源,但每个线程拥有自己独立的程序计数器、寄存器和堆栈。
  通信与同步:线程间的通信和同步相对简单,可以通过共享内存直接访问,但也需要使用适当的同步机制来避免数据竞争和不一致。
  开销:由于线程共享进程的资源,因此创建、销毁和切换线程的开销相对较小。

3. 二者的比较

  独立性:进程是完全独立的,而线程则依赖于进程。
  资源占用:进程占用独立的资源,而线程共享进程的资源。
  开销:进程的创建、销毁和切换开销较大,而线程的开销较小。
  并发性:由于线程的开销较小,因此多线程可以实现更高的并发性。

二、多线程和多进程

  多进程:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,也是操作系统结构的基础。当需要运行多个独立的程序或需要完全隔离的资源时,使用多进程是合适的。例如,在服务器上运行多个独立的服务。其特点为:

  • 独立性:每个进程都有自己的独立地址空间,包括代码、数据、栈等,彼此之间相互隔离,不会相互干扰或影响。
  • 并发性:操作系统可以同时运行多个进程,每个进程独占一定的系统资源,通过切换和调度来实现并发执行。
  • 优势:稳定性高(一个进程的崩溃不会影响其他进程的运行)、数据隔离(进程间数据独立,简化了数据同步的问题)。
  • 劣势:资源消耗大 (每个进程都需要独立的内存空间和系统资源,因此资源消耗相对较大)、切换开销大(进程上下文切换的开销相对较大,可能影响系统的整体性能)。

  多线程:多线程是指从软件或硬件上实现多个线程并发执行的技术。具有多线程能力的计算机能够在同一时间执行多于一个线程,进而提升整体处理性能。当需要在一个程序中并发执行多个任务,且这些任务需要共享某些资源时,使用多线程是合适的。例如,GUI程序中的事件处理、网络编程中的并发连接处理等。其特点大体如下:

  • 并发执行:多个线程可以同时执行,不必等待其他线程完成。
  • 共享资源:多个线程可以共享同一份资源,例如内存、文件等。
  • 独立性:每个线程都有自己的执行上下文和栈空间,彼此之间相互独立。
  • 优势:资源消耗少(线程间共享进程资源,所以资源消耗相对较少)、切换快(线程的上下文切换相对较快,有助于提高CPU的利用率)
  • 劣势:数据同步困难(由于线程间共享数据,数据同步可能会变得复杂和困难)。

三. 代码编写

1. 相关函数

pthread_create( )函数

//功能:创建一个子线程
 #include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
	void *(*start_routine) (void *), void *arg);
  • 参数
    - thread:传出参数,线程创建成功后,子线程的线程ID被写到该变量中。
    - attr : 设置线程的属性,一般使用默认值,NULL
    - start_routine : 函数指针,这个函数是子线程需要处理的逻辑代码
    - arg : 给第三个参数使用,传参
  • 返回值
    - 成功:0
    - 失败:返回错误号。这个错误号和之前errno不太一样。
    - 获取错误号的信息: char * strerror(int errnum);

pthread_exit( )函数

//终止一个线程,在哪个线程中调用,就表示终止哪个线程
#include <pthread.h>
void pthread_exit(void *retval);
  • 参数(retval):需要传递一个指针,作为一个返回值,可以在pthread_join( )中获取到。

  需要注意的是,pthread_exit并不等同于普通的C库函数exit。exit会终止整个进程,而pthread_exit只终止调用它的那个线程。其他线程会继续执行,直到它们也各自调用pthread_exit,或者主线程返回,这时整个进程才会结束。

pthread_join( )函数

//阻塞调用它的线程,直到指定的thread线程终止
int pthread_join(pthread_t thread, void **retval);
  • 参数:
    - thread:需要回收的子线程的ID
    - retval: 接收子线程退出时的返回值
  • 返回值: 成功 – 0
      当thread线程调用pthread_exit并返回时,pthread_join会解除阻塞,并可以通过retval参数获取thread线程的退出状态。如果retval是NULL,那么就不会获取线程的退出状态。

2. 线程同步

  线程同步是指在多个线程之间协调共享资源的访问,以保证数据的一致性和正确性。基本的线程同步原理是通过协调线程之间的访问顺序,确保共享资源的正确访问。当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。线程同步可以避免竞态条件、死锁、饥饿等问题。实现线程同步有多种方式,如临界区、互斥量、信号量和事件等。

  • 临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
  • 互斥量(Mutex):为协调共同对一个共享资源的单独访问而设计,可以指定资源被独占的方式使用。
  • 信号量(Semaphore):为控制一个具有有限数量用户资源而设计,允许多个线程在同一时刻访问同一资源,但需要限制在同一时刻访问此资源的最大线程数目。
  • 事件(Event):用来通知线程有一些事件已发生,从而启动后继任务的开始。

  这些同步方式可以根据具体的应用场景和需求来选择使用,以确保线程之间能够正确地共享和访问资源,提高程序的稳定性和效率,本次实验我们使用互斥量。

3. 互斥量

  互斥量(Mutex,全称互斥锁或互斥对象)是一种用于线程同步的编程工具,它允许一个线程独占某个共享资源,以防止其他线程同时访问。互斥量通常用于保护对共享数据的访问,以避免数据竞争和不一致的问题。通常情况下,我们可以将他理解为一把“锁”,当进入目标线程时,这把锁扣起来,在线程内的任务结束时再把锁打开,其大致流程如下所示。
在这里插入图片描述
  互斥锁和信号量不同的是,它具有互斥锁所有权、递归访问等特性,常用于实现对临界资源的独占式处理, 在任意时刻互斥锁的状态只有两种,开锁或闭锁。当互斥锁被线程持有时,该互斥锁处于闭锁状态,线程获得互斥锁的所有权。当该线程释放互斥锁时, 该互斥锁处于开锁状态,线程失去该互斥锁的所有权。也就是说,同时只有一个线程能获取互斥锁,特别地,持有该互斥锁的线程能够再次获得这个锁而不被阻塞, 这就是互斥锁的递归访问,这个特性与一般的信号量有很大的不同, 在信号量中,由于会不存在可用的信号量,线程递归获取信号量时会发生阻塞,最终形成死锁。
  想要避免死锁,最好遵循以下的规则:

  • 对共享资源操作前一定要获得锁。
  • 完成操作以后一定要释放锁。
  • 尽量短时间地占用锁。
      如果有多个锁, 如获得顺序是ABC连环扣, 释放顺序也应该是ABC。

4. 条件变量

  既然已经掌握了Mutex,我们便再引入它的一个“好伙伴”----条件变量(Condition Variables)。条件量是计算机编程中用于处理并发编程的一种同步机制。在多线程或多进程环境中,条件量通常与互斥锁(mutex)一起使用,以允许线程或进程在满足特定条件之前等待,并在条件满足时被唤醒。它的主要作用是让线程能够在某个条件不成立时进入阻塞状态,等待其他线程改变条件并通知它。一旦条件成立,被阻塞的线程会被唤醒并继续执行。这种机制可以避免线程轮询检查条件是否成立,从而节省CPU资源并提高程序的性能。其大致流程即相关函数如下:
在这里插入图片描述

5. 实验代码

//这是一个多线程案例,其主要目标是通过其中的一个线程进行发送,再经由另一个线程接
收达到回环的目标
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
//初始化
#include<semaphore.h>
static char re_buff[256];
//创建互斥量并初始化,防止持续写入
static pthread_mutex_t tmutex = PTHREAD_MUTEX_INITIALIZER; 
static pthread_cond_t tcond = PTHREAD_COND_INITIALIZER;

static void *my_thread_func(void *data){
    while(1){
    	//上锁
        pthread_mutex_lock(&tmutex);
        //等待条件
        pthread_cond_wait(&tcond,&tmutex);

        printf("rec: %s\n",re_buff);
        //解锁
        pthread_mutex_unlock(&tmutex);
    }
        return NULL;
}

int main(int argc, char **argv){
    pthread_t tid;
    int res;
    //防止主线程长期霸占互斥量
    char buff[256];
    //创建接收线程(若成功返回0)
    res = pthread_create(&tid,NULL,my_thread_func,NULL);
    //验证是否创建成功
    if(res != 0){
        printf("create error!\n");
        return -1;
    }
    //主线程读取标准输入发给接收线程
    while(1){
        fgets(buff,256,stdin);
        //上锁
        pthread_mutex_lock(&tmutex);
        memcpy(re_buff,buff,256);
        //通知接收线程
        pthread_cond_signal(&tcond);
        //解锁
        pthread_mutex_unlock(&tmutex);
    }
    return 0;
}

在这里插入图片描述
注:在gcc -o 编译时需要加上扩展库(-lpthread),例如:

gcc -o thread.o thread.c -lpthread

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

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

相关文章

数据结构-上三角矩阵存储方式[0知识掌握]

目标&#xff1a;看完本文章你将会了解上三角矩阵的存储方式以及矩阵中数据的位置索引号如何求 难点&#xff1a;上三角矩阵的公式推导&#xff0c;上三角任意位置对应的存储位置。 一、准备知识 1.求和公式 前n项和&#xff1a;Sn n(a1an)/2 公差&#xff1a;d后项-前项…

冯喜运:4.16中东对抗风暴下,黄金原油市场何去何从?

黄金行情走势分析&#xff1a;4小时图布林道开始收口&#xff0c;昨日下探至下轨附近&#xff0c;也是此前的起涨低点2320启稳上升&#xff0c;十字K线配合单阳拉起&#xff0c;重新去摸高上轨。目前4小时图处于摸高当中。周线和日线留意多空转换&#xff0c;摸高之后是强势延续…

GPT提示词分享 —— 解梦

&#x1f449; 对你描述的梦境进行解读。 我希望你能充当一个解梦者。我将给你描述我的梦&#xff0c;而你将根据梦中出现的符号和主题提供解释。不要提供关于梦者的个人意见或假设。只提供基于所给信息的事实性解释。 GPT3.5的回答 GPT3.5 &#x1f447; 感觉有点傻&#xf…

5.前后端分离

目录 一、前后端分离上传文件 1.在yml中设置port和localhost 2.如何使用postman测试上传文件的接口 二、如何导出excel文件 ​编辑1.在pom.xml中导包 2.在实体类中给每个字段添加注解&#xff0c;导出表格时&#xff0c;列名将会改为对应的中文 3.controller中方法的具体…

AI大模型日报#0416:李飞飞《2024年人工智能指数报告》、Sora加入Adobe、李彦宏聊百度大模型之路

​导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 刚刚&#xff0c;李飞飞团队发布《2024年人工智能指数报告》&#xff1a;10大趋势&#xff0c;揭示AI大模型的“喜”与“忧” 摘…

origin绘图操作合集

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、图例去掉边框二、柱状图单独选中某一柱子修改颜色&#xff0c;柱状图中设置一个柱子的方法 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参…

【LatentDiffusion 代码详解(1)】LatentDiffusion 的 yaml 解读

YAML 文件提供了一种清晰、简洁且易于理解的方式来描述配置信息&#xff0c;特别适用于机器学习模型的超参数调优和实验管理。 以 Latent Diffusion 官方代码仓库中的 https://github.com/CompVis/latent-diffusion/blob/main/configs/autoencoder/autoencoder_kl_32x32x4.yam…

Spring Task 定时任务(含结合cron 表达式)

目录 一、Spring Task的介绍 二、使用方法 2.1 配置类启用定时任务支持&#xff1a; 2.2 同步定时任务 ​编辑2.3 fixedRate 可以看出不能满足我们的日常需求 那如何让其开启异步呢&#xff08;开启多个线程工作&#xff09; 三、Spring Task 结合cron表达式 3.1 corn 表…

【Linux】解决虚拟机于主机不能共享文件的问题

结论 不要使用xshell使用mobaxterm进行拖拽

2.类和对象

目录 1.类的引入 2.类的定义 3.类的访问限定符及封装 3.1访问限定符 ​编辑 ​编辑 3.2封装 4类的作用域 5.类的实例化 6.类的对象大小的计算 6.1如何计算类对象的大小 6.2类对象的存储方式猜测 6.3 结构体内存对齐规则 7.this指针 7.1this指针的引出 7.2this指针…

uniapp h5项目上传图片到oss(纯前端)

需求&#xff1a;后端给前端一个oss上传地址&#xff0c;前端需要根据getCkOSSToken获取stsToken,使用client.put方法将图片上传成功&#xff0c;并且使用canvas压缩图片 效果图 废话不多说&#xff0c;直接上代码&#xff0c;代码可直接复制&#xff0c;运行 准备工作 cnpm…

Pytorch(GPU版本)简介、安装与测试运行

目录 Pytorch简介Pytorch安装查看CUDA版本Pytorch命令安装Pytorch测试运行Pytorch简介 PyTorch是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。PyTorch既可以看作加入了GPU支持的numpy,同时也可以看成一个拥有自动求导功能的强大的深度神经网络。 2…

中医圆运动规律

目录 人体圆运动营气在十二经脉的运行规律子午流注与圆运动升降结合图 人体圆运动 营气在十二经脉的运行规律 营气在脉中&#xff0c;卫气在脉外 这个顺序也是子午流注的顺序 子午流注与圆运动升降结合图

火绒安全的详细用法

1. 引言 本章将介绍火绒安全软件的基本概述和用法。火绒安全是一款功能强大的安全软件,提供了多种保护功能和工具,可以帮助您保护计算机免受恶意软件、网络攻击和其他安全威胁的侵害。 2. 火绒安全的功能 火绒安全具有以下主要功能: 实时防护:火绒安全提供实时监测和防护…

为硬刚小米SU7,华为智界S7整出了「梅开二度」操作

如今国产中大型新能源轿车市场&#xff0c;在小米 SU7 加入后&#xff0c;可算彻底活了过来。 过去几年&#xff0c;咱们自主新能源品牌在 20-30 万元级轿车上发力明显不足&#xff0c;老牌车厂比亚迪汉几乎以一己之力扛起销量担当。 随着新能源汽车消费升级、竞争加剧&#x…

基于SSM的购物小程序01

4.1系统架构设计 购物系统设计的系统项目的概述设计分析&#xff0c;主要内容有学习平台的具体分析&#xff0c;进行数据库的是设计&#xff0c;数据采用mysql数据库&#xff0c;并且对于系统的设计采用比较人性化的操作设计&#xff0c;对于系统出现的错误信息可以及时做出处…

WordPress 多站点切换域名完整指南:详细步骤和注意事项

因为公司的需要&#xff0c;需要对 WordPress 多站点进行域名切换, 一开始我也找了相关的方案和教程&#xff0c;但是很可惜&#xff0c;国内这一块网上的资料几乎为0&#xff0c;所以我把实现的过程写了一篇文章分享出来&#xff0c;为后来的人铺路。 开始之前&#xff0c;先…

红黑树(Red Black Tree)

红黑树&#xff08;Red Black Tree&#xff09; 红黑树&#xff08;Red Black Tree&#xff09; 是一种自平衡二叉查找树 红黑树是在1972年由Rudolf Bayer发明的&#xff0c;当时被称为平衡二叉B树&#xff08;symmetric binary B-trees&#xff09;后来&#xff0c;在1978年…

文件上传App,H5,小程序多端兼容

插件地址&#xff1a;https://ext.dcloud.net.cn/plugin?id5459 下载lsj-upload插件 代码如下 结构 <lsj-upload :option"option" :size"size" :formats"formats" :debug"debug":instantly"instantly" change"…

Element-Ui的Form表单:Label文本两端对齐,且必填项的*不影响布局

1. HTML 结构 首先&#xff0c;确保你的 HTML 或 Vue 模板中有一个 el-form 组件&#xff0c;类似下面这样&#xff1a; <div id"app"><el-form :model"form" label-width"100px"><el-form-item label"用户名">&l…