Linux(多进程与多线程)

目录

1、进程与线程概念

1.1 进程

1.2 线程

1.3 进程与线程区别

2、多进程

2.1多进程概念

2.2 进程相关API

2.3 多进程编程

3、多线程

3.1 多线程概念

3.2 多线程相关API

3.3 多线程编程


1、进程与线程概念

1.1 进程

在计算机科学中,进程是正在执行中的程序的实例。一个进程包括程序的代码、数据、执行上下文和操作系统分配的资源。进程是操作系统中的最小执行单位,操作系统通过管理和调度进程来实现多任务处理。

以下是关于进程的一些关键概念:

  1. 程序 vs. 进程

    • 程序(Program):是一个静态的代码文件,包含了计算机指令。程序本身并没有在计算机上执行,而只是一组指令的集合。
    • 进程(Process):是程序在计算机上实际运行的实例。进程拥有自己的内存空间、寄存器、执行状态等。
  2. 进程特点

    • 独立性:每个进程都是独立运行的实体,不受其他进程的影响。
    • 并发性:多个进程可以同时执行,操作系统通过时间分片等机制实现并发。
    • 动态性:进程可以创建、运行和结束,具有生命周期。
  3. 进程状态

    • 就绪(Ready):进程已准备好执行,等待分配处理器资源。
    • 运行(Running):进程正在执行指令。
    • 阻塞(Blocked):进程等待某个事件(如输入输出完成)发生。
    • 终止(Terminated):进程执行完毕或被终止。
  4. 进程间通信: 进程可能需要相互通信和协作。常用的进程间通信方式包括管道、信号、共享内存、消息队列和套接字等。

  5. 进程调度: 操作系统负责管理和调度进程的执行。调度算法决定了哪个进程将获得处理器资源,并控制进程之间的切换。

  6. 进程控制块(PCB): PCB 是操作系统用于管理和描述进程的数据结构,包含了进程的状态、程序计数器、寄存器值、内存指针等信息。

进程是操作系统的基础概念,操作系统通过对进程的管理和调度,实现了计算机的多任务处理和资源共享。

1.2 线程

线程(Thread)是操作系统中最小的调度单位,它是进程的一个执行流程,是在进程内部进行调度和执行的基本单元。线程在同一进程内共享该进程的内存空间和资源,但每个线程拥有自己的栈空间和寄存器状态。

以下是关于线程的一些关键概念:

  1. 线程特点

    • 线程是在进程内部创建和管理的。一个进程可以包含多个线程,这些线程共享进程的资源。
    • 线程之间的切换开销较小,因为它们共享同一进程的内存空间和上下文。
    • 线程的创建和销毁通常比进程更快,因为线程共享进程的资源,不需要为每个线程都创建独立的资源。
    • 线程可以用于实现并发执行,提高系统的响应性和资源利用率。
  2. 线程与进程的关系

    • 一个进程可以包含多个线程,这些线程共享进程的代码、数据和资源。
    • 多个线程在同一进程内运行,它们之间可以进行通信和同步。
    • 多个进程则是相互独立的,拥有各自独立的内存空间和资源。
  3. 线程调度: 操作系统负责管理和调度线程的执行。不同的线程调度算法决定了哪个线程将获得处理器资源。

  4. 线程同步: 在多线程编程中,线程之间可能会互相干扰或冲突。线程同步机制,如互斥锁、信号量和条件变量,用于协调线程之间的操作,以确保数据一致性和正确性。

  5. 用户级线程和内核级线程

    • 用户级线程:线程的创建、调度和管理完全由用户程序控制,操作系统对线程无感知。
    • 内核级线程:线程的创建、调度和管理由操作系统控制,操作系统直接管理线程。

线程是操作系统中的基本调度单位,适用于需要并发执行的任务。通过多线程编程,可以充分利用多核处理器的能力,提高程序的性能和响应性。但同时,多线程编程也需要考虑到线程安全和同步的问题。

1.3 进程与线程区别

  1. 资源分配: 进程有独立的资源(内存、文件句柄等),而线程共享所属进程的资源。
  2. 切换开销: 进程之间的切换开销较大,线程之间切换开销较小。
  3. 隔离性: 进程之间相互隔离,一个进程的错误不会影响其他进程;线程共享内存,一个线程的错误可能会影响其他线程。
  4. 通信与同步: 进程通信较复杂,线程之间共享内存,通信和同步更方便但也更容易出错。

通常来说,多线程编程更轻量,可以更好地利用多核处理器,但需要更仔细地处理并发访问共享资源的问题。多进程编程相对来说更安全,但开销较大。选择使用进程还是线程取决于你的应用需求和对多任务处理的优先级。

2、多进程

2.1多进程概念

多个独立的进程在不同的地址空间中运行,相对安全但开销较大。

多进程编程是一种并发编程的方式,它利用操作系统的多进程能力来实现多个任务的并行执行。在多进程编程中,每个任务被封装为一个独立的进程,它们在不同的内存空间中运行,相互之间相对独立。这种方法可以有效利用多核处理器,提高程序的性能和响应性。

2.2 进程相关API

  1. fork() 函数:

    • 作用:创建一个新的子进程,子进程是父进程的副本,执行相同的程序代码。
    • 返回值:在父进程中,返回子进程的 PID;在子进程中,返回 0;如果失败,返回 -1。
    • 头文件:<unistd.h>
  2. exec 函数族(如 execl, execv, execle, execve 等):

    • 作用:用于在当前进程中加载并执行一个新的程序。
    • 使用不同的函数名和参数,支持不同的参数传递方式。
    • 返回值:只在出错时返回 -1,成功执行后不会返回。
  3. wait()waitpid() 函数

    • 作用:等待子进程结束,以获取子进程的退出状态。
    • wait() 阻塞调用进程,直到任意子进程退出。
    • waitpid() 允许指定要等待的子进程的 PID,可以非阻塞等待。
    • 返回值:退出的子进程 PID 或 -1(出错时)。
    • 头文件:<sys/wait.h>
  4. exit() 函数

    • 作用:终止调用进程,并返回一个状态码给父进程。
    • 参数:传递给父进程的状态码。
    • 没有返回值,直接终止进程。
  5. getpid() 函数:

    • 作用:获取当前进程的 PID(进程标识符)。
    • 返回值:当前进程的 PID。
    • 头文件:<unistd.h>
  6. getppid() 函数:

    • 作用:获取当前进程的父进程的 PID。
    • 返回值:父进程的 PID。
    • 头文件:<unistd.h>
  7. kill() 函数:

    • 作用:向指定进程发送信号。
    • 参数:目标进程的 PID 和信号编号。
    • 返回值:成功返回 0,失败返回 -1。
  8. getuid()getgid() 函数:

    • 作用:获取当前进程的用户 ID 和组 ID。
    • 返回值:用户 ID 和组 ID。
    • 头文件:<unistd.h>
  9. setuid()setgid() 函数:

    • 作用:设置当前进程的用户 ID 和组 ID。
    • 参数:要设置的用户 ID 和组 ID。
    • 返回值:成功返回 0,失败返回 -1。
  10. sleep() 函数:

    • 作用:让当前进程休眠一段指定的时间。
    • 参数:休眠时间(秒)。
    • 返回值:休眠完毕后返回剩余休眠时间(0 表示完整休眠,-1 表示休眠被中断)。

2.3 多进程编程

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h> // 包含用于等待子进程的头文件int main() {// 创建第一个子进程// 在父进程中,fork() 函数返回子进程的 PID,而在子进程中,fork() 返回 0。pid_t child1_pid = fork();if (child1_pid == -1) {// fork() 失败时返回 -1,输出错误信息并退出程序perror("Error creating child process");return 1;}if (child1_pid == 0) {// 子进程 1 逻辑printf("Child 1: My PID is %d\n", getpid());// 子进程 1 执行完毕return 0;}// 创建第二个子进程pid_t child2_pid = fork();if (child2_pid == -1) {// fork() 失败时返回 -1,输出错误信息并退出程序perror("Error creating child process");return 1;}if (child2_pid == 0) {// 子进程 2 逻辑printf("Child 2: My PID is %d\n", getpid());// 子进程 2 执行完毕return 0;}// 父进程逻辑printf("Parent: My PID is %d\n", getpid());printf("Parent: Child 1 PID is %d, Child 2 PID is %d\n", child1_pid, child2_pid);// 等待两个子进程执行完毕wait(NULL); // 等待第一个子进程wait(NULL); // 等待第二个子进程return 0;
}

运行结果

3、多线程

3.1 多线程概念

同一进程内的多个线程共享同一地址空间,更轻量但需要注意同步和共享数据。多线程编程可以提高程序的并发性和效率。然而,多线程编程需要注意处理并发访问共享资源的问题,如线程安全和竞态条件。

多线程编程是在同一个进程内创建和管理多个线程,使得这些线程可以并发执行不同的任务。每个线程共享进程的内存空间和资源,但每个线程有自己的栈空间和执行上下文。

3.2 多线程相关API

  1. pthread_create() 函数:

    • 作用:创建一个新线程。
    • 参数:新线程的引用、线程属性、线程函数和参数。
    • 返回值:成功创建线程时返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  2. pthread_join() 函数:

    • 作用:等待一个线程终止,并获取它的退出状态。
    • 参数:要等待的线程的引用、线程退出状态的指针。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  3. pthread_exit() 函数:

    • 作用:终止当前线程,可指定线程退出状态。
    • 参数:线程退出状态。
    • 没有返回值,直接终止线程。
    • 头文件:<pthread.h>
  4. pthread_self() 函数:

    • 作用:获取当前线程的线程 ID。
    • 返回值:当前线程的线程 ID。
    • 头文件:<pthread.h>
  5. pthread_mutex_init() 函数:

    • 作用:初始化互斥锁。
    • 参数:互斥锁引用和互斥锁属性(可为 NULL)。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  6. pthread_mutex_lock()pthread_mutex_unlock() 函数:

    • 作用:锁定和解锁互斥锁。
    • 参数:互斥锁引用。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  7. pthread_mutex_destroy() 函数:

    • 作用:销毁互斥锁。
    • 参数:互斥锁引用。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  8. pthread_cond_init() 函数:

    • 作用:初始化条件变量。
    • 参数:条件变量引用和条件变量属性(可为 NULL)。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  9. pthread_cond_wait()pthread_cond_signal() 函数:

    • 作用:等待和唤醒条件变量。
    • 参数:条件变量引用和互斥锁引用。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>
  10. pthread_cond_destroy() 函数:

    • 作用:销毁条件变量。
    • 参数:条件变量引用。
    • 返回值:成功返回 0,否则返回错误码。
    • 头文件:<pthread.h>

3.3 多线程编程

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define NUM_THREADS 4 //创建线程数量// 共享资源
int shared_counter = 0;
pthread_mutex_t mutex; // 互斥锁// 增加计数器的函数,多个线程会同时调用这个函数
void* increment_counter(void* arg) {for (int i = 0; i < 100000; ++i) {pthread_mutex_lock(&mutex); // 加锁,开始临界区shared_counter++; // 对共享资源进行操作pthread_mutex_unlock(&mutex); // 解锁,结束临界区}return NULL;
}int main() {pthread_t threads[NUM_THREADS]; // 存储线程的数组pthread_mutex_init(&mutex, NULL); // 初始化互斥锁// 创建多个线程for (int i = 0; i < NUM_THREADS; ++i) {pthread_create(&threads[i], NULL, increment_counter, NULL);}// 等待所有线程执行完毕for (int i = 0; i < NUM_THREADS; ++i) {pthread_join(threads[i], NULL);}pthread_mutex_destroy(&mutex); // 销毁互斥锁printf("Final counter value: %d\n", shared_counter);return 0;
}

运行结果(为啥输出了三次?

原因:将测试多线程和多进程的两个源文件编译后在一个main.c 文件中进行了调用,在子函数中进行创建的新进程,在子函数被调用运行结束后还会继续执行父进程中之后的函数,所以测试多线程的代码被调用了三次

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

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

相关文章

【git进阶使用】 告别只会git clone 学会版本控制 ignore筛选 merge冲突等进阶操作

git使用大全 基本介绍git 快速上手一 环境安装&#xff08;默认已安装&#xff09;二 远程仓库克隆到本地1 进入rep文件夹目录2 复制远程仓库地址3 git clone克隆仓库内容到本地4 修改后版本控制4.1 修改文件4.2 git status查看版本库文件状态4.3 git add将文件加入版本库暂存区…

word如何调整页码

文章目录 如何调整页码 如何调整页码 用 word 写报告的时候&#xff0c;经常遇到要求说是要从正文开始才显示页码&#xff0c;那如何实现呢 把鼠标放在我们正文的那一页的顶部&#xff0c;点击 布局 ,再点击分隔符&#xff0c;再点击连续 再点击编译页脚 选择你想要的页脚格式…

netdata监控服务器主机(包括Docker容器)

效果 Docker部署 创建挂载目录 mkdir -p /data/netdata/{netdatacache,netdatalib}docker运行 docker run -d --namenetdata \-p 19999:19999 \-v /data/netdata/netdatalib:/var/lib/netdata \-v /data/netdata/netdatacache:/var/cache/netdata \-v /etc/passwd:/host/etc…

用AI重构的钉钉,“钱”路在何方?

点击关注 文&#xff5c;郝 鑫&#xff0c;编&#xff5c;刘雨琦 钉钉2023年生态大会&#xff0c;离开了两年的无招&#xff0c;遇到了单飞9天的钉钉。 “做小钉钉、做好钉钉、做酷钉钉”&#xff0c;无招重申了钉钉的方向。 无招提到的三点&#xff0c;再加上“高质量增长”…

k3s在线快速安装部署

中文文档&#xff1a;快速入门指南 | K3s 一、k3s父节点安装 设置主机唯一名称 hostnamectl set-hostname 192.168.56.105 开放k3s所需端口 6443 51820 和 51821 在线安装主节点 curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRRORcn…

【openEuler创新项目探索】一个Java端的向量化BLAS库VectorBLAS

VectorBLAS简介 VectorBLAS是一个使用Java语言实现的向量化BLAS高性能库&#xff0c;目前已在openEuler社区开源。 VectorBLAS通过循环展开、矩阵分块和内存布局优化等算法优化&#xff0c;对BLAS函数进行了深度优化&#xff0c;并利用VectorAPI JDK提供的多种向量化API实现。…

Golang Gorm 一对多关系 表结构的建立

Belongs To belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。 例如&#xff0c;应用包含 user 和 company&#xff0c;并且每个 user 能且只能被分配给一个 company。 下面的类型就表示这种关系。 注意&#xff0c;在 U…

C语言-内存分布(STM32内存分析)

C/C内存分布 一、内存组成二、静态区域文本段 &#xff08;Text / 只读区域 RO&#xff09;已初始化读写数据段&#xff08;RW data -- Initialized Data Segment&#xff09;未初始化数据段&#xff08;BSS -- Block Started by Symbol&#xff09; 三、动态区域堆&#xff08…

redis windows 版本安装

1. 下载windows安装包并解压 如果是Linux版本可以直接到官网下载&#xff0c;自3.x起官网和微软网站就没有redis安装包更新了&#xff0c;好在github有开发者在编译发布更新&#xff08;目前最新有5.0.9版本可下&#xff09;&#xff0c;地址&#xff1a;redis windows 5版本下…

华为OD机试 - 求满足条件的最长子串的长度 - 双指针(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

c语言实现堆

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、树1、树的概念2、树的相关概念3、树的表示 二、二叉树1、二叉树概念2、特殊的二叉树3、二叉树的性质4、二叉树的顺序结构5、二叉树的链式结构 三、堆(二叉树…

论文阅读_图形图像_U-NET

name_en: U-Net: Convolutional Networks for Biomedical Image Segmentation name_ch: U-Net&#xff1a;用于生物医学图像分割的卷积网络 addr: http://link.springer.com/10.1007/978-3-319-24574-4_28 doi: 10.1007/978-3-319-24574-4_28 date_read: 2023-02-08 date_publi…