多线程学习(C/C++)

news2024/11/24 5:59:19

1.进程

        运行着的程序就是进程

        进程的特性:1.独立性 2.动态性 3.并发性

        (1)进程的状态

        进程一共有五种状态分别为:创建态,就绪态,运行态,阻塞态(挂起态),退出态(终止态)其中创建态和退出态维持的时间是非常短的,稍纵即逝。我们主要是需要将就绪态, 运行态, 挂起态,三者之间的状态切换搞明白        

        就绪态: 万事俱备,只欠东风(CPU资源)

  • 进程被创建出来了,有运行的资格但是还没有运行,需要抢CPU时间片
  • 得到CPU时间片,进程开始运行,从就绪态转换为运行态。
  • 进程的CPU时间片用完了, 再次失去CPU, 从运行态转换为就绪态。


        运行态:获取到CPU资源的进程,进程只有在这种状态下才能运行

  • 运行态不会一直持续,进程的CPU时间片用完之后, 再次失去CPU,从运行态转换为就绪态
  • 只要进程还没有退出,就会在就绪态和运行态之间不停的切换。

        阻塞态:进程被强制放弃CPU,并且没有抢夺CPU时间片的资格

  • 比如: 在程序中调用了某些函数(比如: sleep()),进程又运行态转换为阻塞态(挂起态)
  • 当某些条件被满足了(比如:slee() 睡醒了),进程的阻塞状态也就被解除了,进程从阻塞态转换为就绪态。

         退出态: 进程被销毁, 占用的系统资源被释放了

  • 任何状态的进程都可以直接转换为退出态。

        创建子进程的过程就是cow(copy-on-write)写时拷贝

        写时拷贝(COW):copy-on-write:多个调用者指向同一块地址空间,如果其中有一个要对地址空间的内容进行修改的话,就会拷贝一个内容、大小和原来地址空间一模一样的地址,然后再让要修改的变量指向拷贝的那一块地址空间,然后再进行修改。写时拷贝的优点:减少资源的占用,缺点:只是将资源的占用延后了

        (2)特殊进程
                1.僵尸进程             

        在一个启动的进程中创建子进程,这时候就有了父子两个进程,父进程正常运行, 子进程先与父进程结束, 子进程无法释放自己的PCB资源, 需要父进程来做这个件事儿, 但是如果父进程也不管, 这时候子进程就变成了僵尸进程。

                2.孤儿进程

        在一个启动的进程中创建子进程,这时候父子进程同时运行,但是父进程由于某种原因先退出了,子进程还在运行,这时候这个子进程就可以被称之为孤儿进程(跟现实是一样的)。

                3.守护进程

        守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。(守护进程是一种特殊的孤儿进程)

1.Linux下查看系统进程信息的命令

ps aux
    - a: 查看所有终端的信息
    - u: 查看用户相关的信息
    - x: 显示和终端无关的进程信息

ps ajx

     - a: 查看所有终端的信息

     -j: 采用工作控制的格式显示进程状况

    - x: 显示和终端无关的进程信息

2.进程函数操作中使用的一些常用函数    

(1)创建子进程函数fork、vfork

#include<sys/type.h>

#include<unistd.h>

pid_t fork(void);

功能:

            在已有的进程基础上又创建一个子进程

参数:

           

返回值:

             成功:

                  >0 子进程的进程号,标识父进程的代码区

                  =0 子进程的代码区

             失败:

                  -1 返回给父进程,子进程不会创建

#include<sys/type.h>

#include<unistd.h>

pid_t vfork(void);

功能:

            在已有的进程基础上又创建一个子进程

参数:

           

返回值:

             成功:

                  >0 子进程的进程号,标识父进程的代码区

                  =0 子进程的代码区

             失败:

                  -1 返回给父进程,子进程不会创建

        

[1]fork与vfork的区别:

1)fork(): 子进程拷贝父进程的堆栈段、数据段,代码段

     vfork(): 子进程与父进程共享资源

2)fork(): 父子进程执行次序不确定

     vfork(): 保证子进程先运行,在调用exec()或exit()之前,与父进程数据共享,在exec()或exit()调用之后,父进程才能运行

(2)获取进程号函数 :getpid、getppid
#include<unistd.h>
#include<sys/types.h>
pid_t getpid(void);
功能:
     用来取得执行目前进程的pid号
参数:
     
返回值:
      目前进程的pid号

#include<unistd.h>

#include<sys/types.h>

pid_t getppid(void);

功能:

        用来取得执行目前进程的父进程的pid号

参数:     

        无

返回值:      

        当前进程的父进程的pid号

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
    int num = 10;
    pid_t pid =  fork();
    //pid_t pid =  vfork();
    if(pid > 0){
        num += 10;
        printf("in parent child pid %d, %d\n",pid, num);
        exit(0); //退出进程
    }else if(0 == pid){
        num += 5;
        printf("in child pid %d, num  %d\n",getpid(), num);
        exit(0); //退出进程
    }else{
        printf("failed\n");
    }
    return 0;
}

运行结果:

 (3)进程回收函数wait、waitpid

        为了避免僵尸进程的产生,一般我们会在父进程中进行子进程的资源回收,回收方式有两种,一种是阻塞方式wait(),一种是非阻塞方式waitpid()

 3.进程间通信的方法

进程间的通信方式有:(一共7种方式)
1.管道:无名管道、有名管道
2.信号:信号 信号量
3.消息队列
4.共享内存
5.套接字

(1)进程间通信——无名管道pipe
         1.创建无名管道函数pipe

#include <fcntl.h>

#include <unistd.h>

int pipe(int pipefd[2])

作用:创建一个匿名管道,用来进程间通信;

参数:

        int pipefd[2]这个数组是一个传出参数;

                pipefd[0] 对应管道的读端;

                pipefd[1] 对应管道的写端;

返回值:

        成功 0;

        失败-1;

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
    int fd[2] = {-1, -1}; //fd[0]是读端 fd[1]是写端
    int res = pipe(fd);
    if(res == -1){
        perror("create pipe failed");
        return -1;
    }
    pid_t pid = fork();
    if(pid > 0){
        wait(NULL); //等待子进程退出
        printf("in parent\n");
        char buf[100] = {0};
        read(fd[0], buf,100);
        printf("recv %s",buf);
        exit(0);
    }else if(pid == 0){
        printf("in child\n");
        write(fd[1], "hello", 5);
        exit(0); //系统退出,退出进程
    }
    return 0; //函数的返回
}

 运行结果:

(2)进程间通信——有名管道mkfifo
        1.创建无名管道函数(mkfifo——创建管道文件)

#include<sys/types.h>
#include<sys/stat.h>

int mkfifo(const char *filename,mode_t mode);

功能:

        创建一个管道文件

参数:

        filename:管道文件名

        mode:管道文件权限

               O_RDONLY:读管道

    O_WRONLY:写管道

    O_RDWR:读写管道

    O_NONBLOCK:非阻塞

返回值:

        若函数成功执行则返回值为0

        失败返回-1

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(){
    int ret = mkfifo("myfifo",0666); //创建管道文件
    if(ret == -1){
        perror("mkfifo");
        return -1;
    }
    int fd = open("myfifo", O_RDWR);
    pid_t pid = fork();
    if(pid > 0){
        wait(NULL);
        printf("in parent\n");
        char buf[100] = {0};
        read(fd, buf,100);
        printf("recv %s",buf);
        exit(0);
    }else if(pid == 0){
        printf("in child\n");
        write(fd, "hello", 5);
        exit(0); //系统退出,退出进程
    }
    return 0; //函数的返回
}

运行结果:

 

(3)进程间通信——信号signal

Linux中的信号:可以用kill -l命令查看 

#include<signal>

typedef void(*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

功能:

        设置某个信号的捕捉行为
参数:
            signum:要捕捉的信号
            handler:捕捉到信号要如何处理
                        SIG_IGN:忽略信号
                        SIG_DFL:使用信号默认的行为

 回调函数:

                这个函数是内核调用,程序员只负责写,捕捉到信号后如何去处理信号。
 回调函数:
             需要程序员实现,提前准备好的,函数的类型根据实际需求,看函数指针的定义不是程序员调用,而是当信号产生,由内核调用函数指针是实现回调的手段,函数实现之后,将函数名放到函数指针的位置

返回值:
            成功返回上一次注册的信号处理函数的地址。第一次调用返回NULL
            失败返回SIG_ERR,设置错误号
            9)SIGKILL 和 19)SIGSTOP 不能被捕捉和忽略

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid, int sig);

功能:

        发送一个信号给进程号为pid的进程

参数:

        pid:进程的id

        sig:要发送信号

返回值:

        成功返回0

        错误返回-1

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<signal.h>

void sighandle(int signum){
    printf("signum is %d\n",signum);
}
int main(){
    pid_t pid = fork();
    if(pid > 0){
        //signal(SIGQUIT,SIG_IGN); //SIG_IGN忽视信号
        //signal(SIGQUIT,SIG_DFL); //SIG_DFL默认的方式去处理
        signal(SIGQUIT,sighandle); //自定义处理
        wait(NULL);
        printf("in parent\n");
        exit(0);
    }else if(pid == 0){
        printf("in child\n");
        kill(getppid(),3);//SIGQUIT == 3 //getppid()获取进程的父进程pid号
        exit(0); //系统退出,退出进程
    }
    return 0; //函数的返回
}

运行结果:

 

(4)消息队列——msgget、msgrcv、msgsnd

        在Linux中查看消息队列命令:ipcs -q 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgget(key_t key, int msgflg);

功能:

        创建或打开消息队列 

参数:

         key:和消息队列关联的key值

        msgflg:

                0:取消息队列标识符,若不存在则函数会报错

                IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符

                IPC_CREAT|IPC_EXCL:如果内核中

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

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

相关文章

7.网络原理之TCP_IP(上)

文章目录 1.网络基础1.1认识IP地址1.2子网掩码1.3认识MAC地址1.4一跳一跳的网络数据传输1.5总结IP地址和MAC地址1.6网络设备及相关技术1.6.1集线器&#xff1a;转发所有端口1.6.2交换机&#xff1a;MAC地址转换表转发对应端口1.6.3主机&#xff1a;网络分层从上到下封装1.6.4主…

文件的编译与链接

目录 翻译环境与链接环境&#xff1a; 翻译环境&#xff1a; 编译器部分&#xff1a; 预处理&#xff1a; 编译&#xff1a; 词法分析&#xff1a; 语法分析&#xff1a; 语义分析&#xff1a; 汇编&#xff1a; 小总结&#xff1a; 链接器部分&#xff1a; 运行环境…

LLMS: 将模型与人类价值观对齐Aligning models with human values

欢迎回来。让我们回到 生成式 AI 项目的生命周期。 上周&#xff0c;你 仔细研究了一种叫做微调的技术。 使用 指令&#xff08;包括路径方法&#xff09;进行微调的目标是 进一步训练 模型&#xff0c;以便它们更好地理解 类似人类的提示并 生成更多类似人类的响应。 与基…

2023版 STM32实战5 基本定时器中断

基本定时器简介与特性 -1-时钟可分频 -2-计数模式只可以选择累加 -3-只可以用来定时&#xff08;含中断&#xff09; 查看时钟源 如图定时器7的时钟最大为72MHZ 定时时间的计算 通用定时器的时间计算公式为 Tout &#xff08;&#xff08;arr1&#xff09;&#xff08;psc1&…

[Framework] Android Binder 工作原理

Binder 是 Android 系统中主要的 IPC 通信方式&#xff0c;其性能非常优异。但是包括我在内的很多开发者都对它望而却步&#xff0c;确实比较难&#xff0c;每次都是看了忘&#xff0c;忘了看&#xff0c;但是随着工作的时间约来越长&#xff0c;每次看也都对 Binder 有新的认识…

【图像处理】SIFT角点特征提取原理

一、说明 提起在OpenCV中的特征点提取&#xff0c;可以列出Harris&#xff0c;可以使用SIFT算法或SURF算法来检测图像中的角特征点。本篇围绕sift的特征点提取&#xff0c;只是管中窥豹&#xff0c;而更多的特征点算法有&#xff1a; Harris & Stephens / Shi–Tomasi 角点…

一种节约存储空间的技术——数据压缩

数据压缩是指&#xff1a;通过特定的算法&#xff0c;将计算的中的文件大小得到降低的一种机制。 目前生活中最常见的应用例子&#xff0c;比如&#xff1a;你通过聊天软件将一张图片发送给好友&#xff0c;再选择发送图片的时候&#xff0c;有一个选项为是否发送原图&#xf…

FL Studio21.1电脑试用体验版音乐制作软件

我一直以来对音乐艺术都很感兴趣。最近我接触到了一款名为 FL Studio 的电脑版音乐制作软件&#xff0c;深感其强大功能和广泛适用性。通过使用这款软件&#xff0c;我不仅深入了解了音乐制作的过程与技巧&#xff0c;也加深了对音乐创作的理解。 FL Studio 最初是一款针对 MI…

Flutter笔记 - ListTile组件及其用法

Flutter笔记 ListTile组件及其用法 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133411883 目 录 1. …

leetCode 213. 打家劫舍 II 动态规划 房间连成环怎么偷呢?

213. 打家劫舍 II - 力扣&#xff08;LeetCode&#xff09; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装…

【Java 进阶篇】深入理解 SQL 聚合函数

在 SQL 数据库中&#xff0c;聚合函数是一组强大的工具&#xff0c;用于处理和分析数据。它们可以帮助您对数据进行统计、计算总和、平均值、最大值、最小值等操作。无论您是数据库开发者、数据分析师还是希望更好地了解 SQL 数据库的用户&#xff0c;了解聚合函数都是非常重要…

三个要点,掌握Spring Boot单元测试

单元测试是软件开发中不可或缺的重要环节&#xff0c;它用于验证软件中最小可测试单元的准确性。结合运用Spring Boot、JUnit、Mockito和分层架构&#xff0c;开发人员可以更便捷地编写可靠、可测试且高质量的单元测试代码&#xff0c;确保软件的正确性和质量。 一、介绍 本文…

(SAR)Sentinel-1影像自动下载

基于ASF网站提供的python代码&#xff0c;实现Sentinel-1影像的自动下载&#xff1b; 1、登录ASF网站 登录Sentinel-1影像ASF网站&#xff1a;https://search.asf.alaska.edu/&#xff1b; 点击网站最右侧Sign in图标&#xff0c;进行用户注册&#xff1b; 注册完用户之后&…

基于Vue+ELement实现增删改查案例与表单验证(附源码)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《ELement》。&#x1f3af;&#x1f3af; &#x1…

I2C外设

I2C的总结 I2C优点&#xff1a; 接口线少只有两根线&#xff0c;控制方式简单&#xff0c;通信速率较高&#xff1b; I2C 是飞利浦公司开发的两线式串行总线&#xff1b; I2C缺点&#xff1a; 硬件比较复杂&#xff0c;稳定性不太好&#xff0c;程序移植有点麻烦&#xff…

自定义v-resize指令并发布到NPM

自定义Vite库并发布到NPM 封装useResize 用于监听绑定元素的宽高变化&#xff0c;当元素宽高发生变化时触发回调并获取最新的宽高 新建项目 结合上面学到的 Hook 和 自定义指令封装一个监听元素宽高变化的指令&#xff0c;并发布到 npm 项目结构 useResize ├…

jQuery核心卷

目录 一.jQuery引用 二.jQuery语法 三.元素的属性 1.attr()方法 2.使用removeAttr()方法删除HTML元素的属性 3.使用text()方法设置HTML元素的文本内容 四.CSS元素控制 1.使用css()方法获取和设置css属性 2.与CSS类别有关的方法 3.获取和设置HTML元素的尺寸 4.获取和…

html 边缘融合加载

html 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>边缘融合加载</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {height: 100vh;padding-bottom: 80px;b…

No141.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【STM32】IAP升级00 预备知识

IAP&#xff08;In Application Programming&#xff09;简介 Flash够大的情况下&#xff0c;上电后的程序通过修改 MSP 的方式&#xff0c;可以在一块Flash上存在多个功能差异的程序。 IAP是为了在执行正常功能前&#xff0c;为了升级功能&#xff0c;提前运行的一段程序。这…