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

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

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

相关文章

自然语言处理——情绪检测数据集

一、重要性及意义 情绪检测的重要性和意义体现在多个方面&#xff0c;不仅对于个人日常生活有深远影响&#xff0c;也在多个行业和领域中扮演着关键角色。以下是情绪检测的重要性和意义的具体体现&#xff1a; 提高人机交互体验&#xff1a; 在人工智能和机器学习驱动的系统中…

企业图纸管理软件,企业图纸管理软件有哪些推荐?

企业图纸管理软件是一种专门用于组织、存储、管理和共享企业图纸及相关文档的工具。这类软件可以帮助企业实现图纸的集中化、规范化管理&#xff0c;提高工作效率&#xff0c;降低管理成本。 企业图纸管理软件的核心功能通常包括以下几个方面&#xff1a; 集中化管理&#xff1…

基于SpringBoot+Vue的卓越导师双选系统设计与实现(源码+文档+包运行)

一.系统概述 如今的信息时代&#xff0c;对信息的共享性&#xff0c;信息的流通性有着较高要求&#xff0c;因此传统管理方式就不适合。为了让导师选择信息的管理模式进行升级&#xff0c;也为了更好的维护导师选择信息&#xff0c;卓越导师双选系统的开发运用就显得很有必要。…

基于LNMP部署wordpress

目录 一.环境准备 二.配置源并安装 三.配置Nginx 四.配置数据库 五.上传源码并替换 六.打开浏览器&#xff0c;输入虚拟机ip访问安装部署 七.扩展增加主题 一.环境准备 centos7虚拟机 关闭防火墙和seliunx stop firewalld #关闭防火墙 setenforce 0 …

记录一次内存溢出

1、查看catalina相关日志&#xff0c;确定关键字相关行号 文件&#xff1a;catalina.out命令1&#xff1a;cat -n catalina.out |grep -a OutOfMemoryError与内存溢出相关的如上&#xff0c;每一个行号其实都对应到具体时间点。可以发现&#xff0c;这个范围相符合&#xff1…

temux安装debian自用记录

http://ip:9001/ user/123 http://ip:5705/index admin/drpy 一、安装Ubuntu1804 1&#xff0e;首先安装termux.app 2&#xff0e;启动该app&#xff0c;输入命令 curl -Lo l l.tmoe.me; sh l 3&#xff0e;运行过程中连续选“Y”&…

【学习笔记十三】EWM常见上架策略介绍

一、手工维护上架策略 系统不确定Storage type 和 bin&#xff0c;需要在创建仓库任务时或者确认仓库任务时手工输入仓位 1.后台配置-定义存储类型的类型0010 ①存储行为&#xff1a;标准仓位 ②入库规则&#xff1a;空仓未或添加至现有库存/空仓位 ③通用仓库任务&#x…

【学习笔记十二】EWM上架仓位确定逻辑及操作演示

一、前言 关于EWM上架仓位确定的过程&#xff0c;我在【学习笔记十一】EWM上架目标仓位确定过程及配置-CSDN博客中讲到了 EWM根据仓库类型&#xff08;storage type&#xff09;、仓库分区&#xff08;storage section&#xff09;和上架策略&#xff08;putaway strategies&…

WordPress网站上添加看板娘

续接上篇——基于LNMP部署wordpress-CSDN博客 目录 一.下载并解压 二.设置头文件 修改header.php 修改配置文件footer.php 三.将你设置的主题包上传到/usr/share/nginx/html/wp-content这个目录里 四.扩展——将看板娘修改到左侧 一.下载并解压 [rootaliyun ~]# wget htt…

提升数据质量的三大要素:清洗prompt、数据溯源、数据增强(含Reviewer2和PeerRead)​

前言 我带队的整个大模型项目团队超过40人了&#xff0c;分六个项目组&#xff0c;每个项目组都是全职带兼职&#xff0c;且都会每周确定任务/目标/计划&#xff0c;然后各项目组各自做任务拆解&#xff0c;有时同组内任务多时 则2-4人一组 方便并行和讨论&#xff0c;每周文档…

Adobe Premiere 2015 下载地址及安装教程

Premiere是一款专业的视频编辑软件&#xff0c;由Adobe Systems开发。它为用户提供了丰富的视频编辑工具和创意效果&#xff0c;可用于电影、电视节目、广告和其他多媒体项目的制作。 Premiere具有直观的用户界面和强大的功能&#xff0c;使得编辑和处理视频变得简单而高效。它…

算法库应用-有序单链表插入节点

学习源头: 模仿贺利坚老师单链表排序文章浏览阅读5.9k次。  本文针对数据结构基础系列网络课程(2)&#xff1a;线性表中第11课时单链表应用举例。例&#xff1a;拆分单链表 &#xff08;linklist.h是单链表“算法库”中的头文件&#xff0c;详情单击链接…&#xff09;//本程…