Linux 二十一章

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

非阻塞等待

当父进程进行非阻塞等待的时候,父进程完成其他的任务,比如download、printlog、show

进程等待的必要性

进程程序替换

execl

execlp

execv

execvp

替换c++程序

替换shell语言程序

exec族函数为什么可以替换不同语言的程序?

当一个程序运行的整个过程


非阻塞等待

在 Linux 中,可以使用非阻塞方式等待子进程退出或状态改变。这通常通过设置 waitpid() 函数的选项参数中的 WNOHANG 标志来实现。这样,waitpid() 函数将立即返回,而不会阻塞当前进程。

事例

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
void Worker(int cnt)
{
        printf("I am a child ,pid: %d, cnt:%d\n",getpid(),cnt);
        
}
int main()
{
        pid_t id=fork();
        if(id==0)
        //child
        {
                int cnt=5;
                while(cnt--)
                {
                        Worker(cnt);
                        sleep(2);
                }
                exit(0);
        }

        while(1)
        {
        //fateher
        int status=0;
        pid_t rid=waitpid(id,&status,WNOHANG);
        if(rid>0)
        {
                printf("child quit success,exit code:%d exit sign:%d\n",(status>>8)&0xFF,status&0x7F);
        }
        else if(rid==0)
        {
                printf("father do other thing......\n");
        }
        else
        {
                printf("wait fail\n");
        }
        sleep(1);
        }
        return 0;
}



[BCH@hcss-ecs-6176 11_7]$ ./myprocess
father do other thing......
I am a child ,pid: 20429, cnt:4
father do other thing......
I am a child ,pid: 20429, cnt:3
father do other thing......
father do other thing......
I am a child ,pid: 20429, cnt:2
father do other thing......
father do other thing......
I am a child ,pid: 20429, cnt:1
father do other thing......
father do other thing......
I am a child ,pid: 20429, cnt:0
father do other thing......
father do other thing......
child quit success,exit code:0 exit sign:0
wait fail
wait fail
wait fail
wait fail
wait fail
wait fail
wait fail
wait fail

[BCH@hcss-ecs-6176 ~]$ while :; do ps ajx | grep myprocess | grep -v grep ; sleep 1 ; echo "================================="; done
=================================
=================================
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
20428 20429 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess
=================================
 2499 20428 20428  2499 pts/4    20428 S+    1000   0:00 ./myprocess

当父进程进行非阻塞等待的时候,父进程完成其他的任务,比如download、printlog、show

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

//定义父进程的任务的个数
#define TASK_NUM 5

//重定义函数指针类型
typedef void(*task_t)();

//这里的这些功能并没有真正实现,而是输出一段字符串
//执行下载的任务
void download()
{
        printf("this is a download task is running!\n");
}

//执行写入的任务
void printlog()
{
        printf("this is a write log task is running!\n");
}

//执行查看的任务
void show()
{
        printf("this is a info task is runing!\n ");
}

//将函数指针数组初始化
void initTask(task_t tasks[])
{
        int i=0;
        for(;i<TASK_NUM;i++)
        {
                tasks[i]=NULL;
        }
}

//添加任务到,函数指针数组中
int addTask(task_t tasks[],task_t t)
{
        int i=0;
        for(;i<TASK_NUM;i++)
        {
                if(tasks[i]==NULL)
                {
                        tasks[i]=t;
                        return 1;
                }

        }
        return 0;
}

//执行函数指针数组里的任务
void executeTask(task_t tasks[],int num)
{
        int i=0;
        for(;i<num;i++)
        {
                if(tasks[i])
                        tasks[i]();
        }
}

//子进程的执行的任务
void Worker(int cnt)
{
        printf("I am a child ,pid: %d, cnt:%d\n",getpid(),cnt);
        
}

int main()
{
        //创建函数指针数组,用于存储各种任务(函数)
        task_t tasks[TASK_NUM];
        initTask(tasks);
        addTask(tasks,download);
        addTask(tasks,printlog);
        addTask(tasks,show);
        
        //创建子进程,id>0执行父进程,id==0执行子进程
        pid_t id=fork();
        if(id==0)
        //child
        {
                int cnt=5;
                while(cnt--)
                {
                        Worker(cnt);
                        sleep(1);
                }
                _exit(0);
        }
        while(1)
        {
            //fateher
            int status=0;//记录子进程退出的退出码和信号
            pid_t rid=waitpid(id,&status,WNOHANG);//通过waitpid系统调用去等待子进程,采用WNOHANG非阻塞的方式等待
            if(rid>0)
            {
                    //wait success, child quit now
                    printf("child quit success,exit code:%d exit sign:%d\n",(status>>8)&0xFF,status&0x7F);
            }
            else if(rid==0)
            {
                    printf("##############################################################################################\n");
                    //wait success, but child not quit
                    printf("father do other thing......\n");
                    executeTask(tasks,TASK_NUM);//也可以在内部进行自己移除&&新增对应的任务
                    printf("##############################################################################################\n");
            }
            else
            {
                    //wait failed, child unknow
                    printf("wait fail\n");
            }
            sleep(1);
        }
        return 0;
}


[BCH@hcss-ecs-6176 11_7]$ ./myprocess
##############################################################################################
father do other thing……//说明此时rid==0,父进程开始执行其他任务
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
I am a child ,pid: 23948, cnt:4
##############################################################################################
father do other thing......
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
I am a child ,pid: 23948, cnt:3
##############################################################################################
I am a child ,pid: 23948, cnt:2
father do other thing......
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
I am a child ,pid: 23948, cnt:1
##############################################################################################
father do other thing......
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
I am a child ,pid: 23948, cnt:0
##############################################################################################
father do other thing......
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
##############################################################################################
father do other thing......
this is a download task is running!
this is a write log task is running!
this is a info task is runing!
 ##############################################################################################
child quit success,exit code:0 exit sign:0//rid>0,此时子进程退出,父进程接收到子进程的退出信息和退出码
wait fail//子进程结束,waitpid捕获不到该子进程的信息,所以rid<0
wait fail

进程等待的必要性

如果不进行进程的等待,有可能形成僵尸进程

进程等待我们现在一般使用的阻塞等待,因为阻塞等待足够简单!

进程程序替换

我们所创建的所有子进程,执行的代码,都是父进程代码的一部分!

如果我们想让子进程执行新的程序呢???执行全新的代码和访问全新的数据,不在和父进程有瓜葛

那需要程序替换

execl

execl 是一个系统调用,用于在当前进程中执行一个新的程序。它的原型如下:

#include <unistd.h>
int execl(const char *path, const char *arg0, const char *arg1, ..., const char *argn, (char *) NULL);

path 参数是要执行的新程序的路径。
arg0, arg1, ..., argn 是新程序的命令行参数,最后一个参数必须是空指针 (char *) NULL,表示参数列表的结束。


execl 函数会取代当前进程的内存映像,加载并执行指定路径的新程序,新程序的参数由 arg0 到 argn 指定。执行 execl 后,当前进程的代码、数据、堆栈等内容都被替换为新程序的内容,新程序开始执行。

如果 execl 函数执行成功,它不会返回;如果发生错误,返回值为 -1,并且设置全局变量 errno 表示具体的错误类型。

这个函数在创建子进程后常用于在子进程中执行其他程序,因为在子进程中执行 execl 后,子进程的内容就被替换为新程序的内容,从而达到执行其他程序的效果。

事例

我们可以用“语言”调用其他程序
[BCH@hcss-ecs-6176 11_7_1]$ cat test.c
#include<stdio.h>
#include<unistd.h>
int main()
{
         printf("pid:%d,excel command begin\n",getpid());
         execl("/usr/bin/ls","ls","-a","-l",NULL);//execl调用的ls程序
         printf("pid:%d,excel command end\n",getpid());
         return 0;
}

[BCH@hcss-ecs-6176 11_7_1]$ ./test
pid:4066,excel command begin
总用量 24
drwxrwxr-x  2 BCH BCH 4096 11月 10 18:05 .
drwx------ 26 BCH BCH 4096 11月 10 18:04 ..
-rwxrwxr-x  1 BCH BCH 8464 11月 10 18:05 test
-rw-rw-r--  1 BCH BCH  208 11月 10 18:04 test.c

替换的底层原理

证明程序替换并没有创建新进程

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                execl("/usr/bin/ls","ls","-a","-l",NULL);
                printf("pid:%d,excel command end\n",getpid());
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:11527,excel command begin
总用量 56
drwxrwxr-x  2 BCH BCH  4096 11月 10 18:08 .
drwx------ 26 BCH BCH  4096 11月 10 18:04 ..
-rw-rw-r--  1 BCH BCH  1928 11月 10 16:30 1
-rw-rw-r--  1 BCH BCH    74 11月  9 22:13 Makefile
-rwxrwxr-x  1 BCH BCH  8624 11月 10 17:59 myprocess
-rw-rw-r--  1 BCH BCH  2672 11月 10 17:59 myprocess.c
-rw-r--r--  1 BCH BCH 12288 11月 10 18:08 .myprocess.c.swo
-rw-r--r--  1 BCH BCH 12288 11月  8 23:05 .myprocess.c.swp
wait success,rid:11527

pid和rid的值一样,可以说明,execl的时候没有创建新的进程

当父进程创建子进程,子进程发生了替换的时候,这里发生的写时拷贝,写时拷贝的同时不仅要拷贝数据还要拷贝代码,这样子进程发生程序替换的时候,不会影响父进程

子进程怎么知道,要从新的程序的最开始执行?

他怎么知道最开始的地方在哪里呢?

Eip寄存器:虽然cpu中只有一个eip寄存器,但是可以存储多组数据,也就是每一个进程都都会有一组数据

当替换进来的程序,eip会找到entry,可执行程序的入口地址

注意:当通过execl程序替换成功了,则后续代码没有机会再执行了!因为被替换掉了!

如果替换失败,会有一个返回值-1,替换成功,不会返回

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                int n=execl("/usr/bin/lsss","lsss","-a","-l",NULL);//execl程序替换错误时,n接收返回值
                printf("pid:%d,excel: n=%d  command end\n",getpid(),n);
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:29364,excel command begin
pid:29364,excel: n=-1  command end
wait success,rid:29364

execlp

execlp 是一个系统调用,与 execl 类似,用于在当前进程中执行一个新的程序,但它可以搜索 PATH 环境变量指定的路径来寻找可执行文件。它的原型如下:

#include <unistd.h>
int execlp(const char *file, const char *arg0, const char *arg1, ..., const char *argn, (char *) NULL);
file 参数是要执行的新程序的文件名或路径。如果 file 中不包含斜杠 /,则 execlp 函数会在 PATH 环境变量指定的路径中搜索与 file 匹配的可执行文件。
arg0, arg1, ..., argn 是新程序的命令行参数,最后一个参数必须是空指针 (char *) NULL,表示参数列表的结束。


与 execl 类似,execlp 函数也会取代当前进程的内存映像,加载并执行指定路径的新程序,新程序的参数由 arg0 到 argn 指定。执行 execlp 后,当前进程的代码、数据、堆栈等内容都被替换为新程序的内容,新程序开始执行。

如果 execlp 函数执行成功,它不会返回;如果发生错误,返回值为 -1,并且设置全局变量 errno 表示具体的错误类型。

execlp 常用于在当前进程中执行其他程序,且无需指定程序的绝对路径,只需指定程序的名称即可,因为它会在 PATH 环境变量指定的路径中搜索可执行文件。

事例

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                //execl("/usr/bin/ls","ls","-a","-l",NULL);
                execlp("ls","ls","-a","-l",NULL);//第一个ls是文件名,第二个ls是命令行调用ls指令
                printf("pid:%d,excel command end\n",getpid());
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:13889,excel command begin
总用量 56
drwxrwxr-x  2 BCH BCH  4096 11月 11 00:05 .
drwx------ 26 BCH BCH  4096 11月 11 00:05 ..
-rw-rw-r--  1 BCH BCH  1928 11月 10 16:30 1
-rw-rw-r--  1 BCH BCH    74 11月  9 22:13 Makefile
-rwxrwxr-x  1 BCH BCH  8624 11月 11 00:05 myprocess
-rw-rw-r--  1 BCH BCH  2710 11月 11 00:05 myprocess.c
-rw-r--r--  1 BCH BCH 12288 11月 10 23:44 .myprocess.c.swo
-rw-r--r--  1 BCH BCH 12288 11月  8 23:05 .myprocess.c.swp
wait success,rid:13889

execv

execv 是一个系统调用,用于在当前进程中执行一个新的程序。它的原型如下:

#include <unistd.h>
int execv(const char *path, char *const argv[]);
path 参数是要执行的新程序的路径。
argv 是一个以 NULL 结尾的字符串数组,其中第一个元素是要执行的新程序的名称,后续元素是新程序的命令行参数。

execv 函数会取代当前进程的内存映像,加载并执行指定路径的新程序,新程序的参数由 argv 指定。执行 execv 后,当前进程的代码、数据、堆栈等内容都被替换为新程序的内容,新程序开始执行。

如果 execv 函数执行成功,它不会返回;如果发生错误,返回值为 -1,并且设置全局变量 errno 表示具体的错误类型。

execv 与 execl 和 execlp 的不同之处在于它接受一个字符串数组作为参数,而不是逐个列出参数。这使得在运行时动态构建参数列表更为方便。

事例

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                //
                
                char* const argv[]={
                        "ls",
                        "-a",
                        "-l",
                        NULL
                };
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                //execl("/usr/bin/ls","ls","-a","-l",NULL);
                //execlp("ls","ls","-a","-l",NULL);
                execv("/usr/bin/ls",argv);
                printf("pid:%d,excel command end\n",getpid());
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:1798,excel command begin
总用量 56
drwxrwxr-x  2 BCH BCH  4096 11月 11 00:15 .
drwx------ 26 BCH BCH  4096 11月 11 00:15 ..
-rw-rw-r--  1 BCH BCH  1928 11月 10 16:30 1
-rw-rw-r--  1 BCH BCH    74 11月  9 22:13 Makefile
-rwxrwxr-x  1 BCH BCH  8624 11月 11 00:15 myprocess
-rw-rw-r--  1 BCH BCH  2824 11月 11 00:15 myprocess.c
-rw-r--r--  1 BCH BCH 12288 11月 10 23:44 .myprocess.c.swo
-rw-r--r--  1 BCH BCH 12288 11月  8 23:05 .myprocess.c.swp
wait success,rid:1798

execvp

execvp 是一个系统调用,与 execv 类似,用于在当前进程中执行一个新的程序,但它可以搜索 PATH 环境变量指定的路径来寻找可执行文件。它的原型如下:

#include <unistd.h>
int execvp(const char *file, char *const argv[]);
file 参数是要执行的新程序的文件名或路径。如果 file 中不包含斜杠 /,则 execvp 函数会在 PATH 环境变量指定的路径中搜索与 file 匹配的可执行文件。
argv 是一个以 NULL 结尾的字符串数组,其中第一个元素是要执行的新程序的名称,后续元素是新程序的命令行参数。


与 execv 类似,execvp 函数也会取代当前进程的内存映像,加载并执行指定路径的新程序,新程序的参数由 argv 指定。执行 execvp 后,当前进程的代码、数据、堆栈等内容都被替换为新程序的内容,新程序开始执行。

如果 execvp 函数执行成功,它不会返回;如果发生错误,返回值为 -1,并且设置全局变量 errno 表示具体的错误类型。

execvp 常用于在当前进程中执行其他程序,且无需指定程序的绝对路径,只需指定程序的名称即可,因为它会在 PATH 环境变量指定的路径中搜索可执行文件。

替换c++程序

我们用自己写的c语言程序,去程序替换成我们自己编写的C++程序

[BCH@hcss-ecs-6176 11_7]$ cat test.cc
#include<iostream>
using namespace std;
int main()
{
        cout<<"hello c++"<<endl;
        cout<<"hello c++"<<endl;
        cout<<"hello c++"<<endl;
        cout<<"hello c++"<<endl;
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                excel("./mytest" , "mytest",NULL);
                printf("pid:%d,excel command end\n",getpid());
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}


[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:32180,excel command begin
hello c++
hello c++
hello c++
hello c++
wait success,rid:32180

替换shell语言程序

test.sh是shell下面的脚本语言

[BCH@hcss-ecs-6176 11_7]$ cat test.sh
#!/usr/bin/bash //开头必须以#!,后面跟上系统指令或者自己写的程序路径

echo "hello world"
touch file1 file2 file3
echo "hello done"

命令行运行的时候
1)bash test.sh

2)也可以chmod +x test.sh
./test.sh

我们用自己写的c语言程序,去程序替换成我们自己编写的shell脚本程序

[BCH@hcss-ecs-6176 11_7]$ cat test.sh
#!/usr/bin/bash //开头必须以#!,后面跟上系统指令或者自己写的程序路径


echo "hello world"
touch file1 file2 file3
echo "hello done"

[BCH@hcss-ecs-6176 11_7]$ cat myprocess.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
        pid_t id=fork();
        if(id==0)
        {
                //child
                printf("pid:%d,excel command begin\n",getpid());
                sleep(3);
                excel("/usr/bin/bash" , "bash", "test.sh",NULL);
                printf("pid:%d,excel command end\n",getpid());
        }
        else
        {
                //father
                pid_t rid=waitpid(-1,NULL,0);
                if(rid>0)
                {
                        printf("wait success,rid:%d\n",rid);
                }
        }
        return 0;
}

[BCH@hcss-ecs-6176 11_7]$ ./myprocess
pid:31838,excel command begin
hello world//脚本语言运行成功
hello done
wait success,rid:31838

exec族函数为什么可以替换不同语言的程序?

exce*(*是通配符)

不管用什么语言编写的程序(C/C++、bash、java、python等),只要在os中都可以进行进程替换

exec 系列函数可以替换不同语言的程序,是因为它们是操作系统级别的系统调用,与编程语言无关。这些函数在操作系统层面实现了程序的加载和执行,不依赖于特定的编程语言。

当调用 exec 系列函数时,操作系统会负责加载指定的可执行文件,并在当前进程的上下文中执行该文件。这意味着,无论是用 C、Python、Java 还是其他编程语言编写的程序,只要它们是可执行文件,并符合操作系统的执行要求,就可以被 exec 函数加载和执行。

因此,exec 系列函数是跨语言的,可以用于替换任何可执行文件,而不仅仅局限于特定语言的程序。这也使得在一个编程环境中,通过调用 exec 函数,可以方便地与其他编程语言的程序进行交互和整合。

当一个程序运行的整个过程

一个程序被运行(形成进程),首先第一步,是要创建内核数据结构(pcb、页表等),然后第二步,将程序的代码和数据加载到内存中,页表再一一映射

有时,有些程序没有被运行时,只需要创建内核数据结构(pcb、页表等),页表没有映射物理内存

  🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

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

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

相关文章

上市企业扣非净利润是什么意思,可以反映什么问题?

扣非净利润&#xff0c;全称“扣除非经常性损益后的净利润”&#xff0c;是指企业在剔除与正常经营无关的、偶然发生的损益后所得到的利润。这些非经常性损益包括但不限于政府补贴、处置长期资产、税收返还等。 扣非净利润的计算公式为&#xff1a;扣非净利润 净利润 - 非经常…

python:机器学习特征优选

作者&#xff1a;CSDN _养乐多_ 在Python中进行机器学习特征选择的方法有很多种。以下是一些常用的方法&#xff1a; 过滤法&#xff08;Filter Methods&#xff09;&#xff1a;通过统计方法或者相关性分析来评估每个特征的重要性&#xff0c;然后选择最相关的特征。常用的…

基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 遗传算法&#xff08;GA&#xff09;原理 4.2 BP神经网络原理 4.3 遗传优化BP神经网络结合应用 4.4 遗传算法简要改进 5.完整程序 1.程序功能描述 基于改进遗传优化的BP神经网络金融…

电机控制系列模块解析(17)—— 速度环

一、电机转速控制 电机控制的速度环是整个电机控制系统中的外环&#xff0c;其主要任务是根据设定的转速指令值&#xff08;目标速度&#xff09;与实际电机转速之间的偏差&#xff0c;调整电流环的参考值&#xff08;d轴电流Id或q轴电流Iq&#xff0c;涉及类似单电流环的弱磁…

OpenCampass评测实战 作业

按照如下教程文档操作即可&#xff1a;https://aicarrier.feishu.cn/wiki/NxUOwnLuvi0clykyzj7ccSHPndb

JavaScript解决精度问题-math.js-使用入门

JavaScript精度失真案例 0.1+0.2 结果是:0.300000000000000041-0.9 结果是:0.099999999999999984.10*100 结果是:409.999999999999946.10/0.1 结果是:60.99999999999999大数计算 9007199254740992+1 结果是9007199254740992 JavaScript 浮点数运算结果不对,因浮点数的存储…

物料厘不清?企业如何做好“物料管理”

物料包括原材料、半成品、成品、辅助用品以及生产过程中必然产生的边角余料、废料等。在制造企业中&#xff0c;各个部门的业务流程几乎都要用到物料&#xff1a; 销售和订单录入部门要通过物料确定客户定制产品的构形&#xff1b; 计划部门要根据物料来计划物料和能力的需求…

AI绘画ComfyUI工作流安装教程,新手入门安装部署教程

ComfyUI 是专为 Stable Diffusion 打造的图形用户界面&#xff08;GUI&#xff09;&#xff0c;采用了基于节点的操作方式。用户可以通过连接不同的模块&#xff08;即节点&#xff09;来创建复杂的图像生成流程。这些节点涵盖了多样的功能&#xff0c;包括加载检查点模型、输入…

卧龙搞怪作妖,图形化编程桌面内测探秘故事

在一间古朴的办公室内&#xff0c;卧龙与凤雏相对而坐&#xff0c;悠闲地品着茶。茶香袅袅&#xff0c;弥漫在空气中。 “凤雏贤弟啊&#xff0c;你可曾忆起往昔在那图形化编程桌面&#xff0c;咱们行产品内测之时&#xff0c;那乱象丛生之景呢&#xff1f;”卧龙微微眯眼&…

深度解析互联网医疗源码:视频问诊APP开发技术剖析

视频问诊APP作为在线医疗其中的重要一环&#xff0c;正在改变人们就医的方式。今天&#xff0c;我将为大家详解互联网医疗源码&#xff0c;探讨视频问诊APP开发技术&#xff0c;揭示其背后的原理和关键技术。 一、视频问诊APP的基本功能 视频问诊APP作为一种新型的医疗服务平台…

JAVA语言开发的(智慧校园系统源码)智慧校园的痛点、智慧校园的安全应用、智慧校园解决方案

一、智慧校园的痛点 1、信息孤岛问题&#xff1a;由于校园内各部门或系统独立开发&#xff0c;缺乏统一规划和标准&#xff0c;导致数据无法有效整合和共享&#xff0c;形成了信息孤岛。 2、技术更新与运维挑战&#xff1a;智慧校园的建设依赖于前沿的信息技术&#xff0c;如云…

Python进阶之-jinja2详解

✨前言&#xff1a; &#x1f31f;什么是jinja2&#xff1f; Jinja2 是一个强大的 Python 模版引擎&#xff0c;主要用于生成HTML或其他文本文件。这个库非常适合开发动态网站和Web应用的视图层&#xff0c;因为它支持逻辑操作如循环和条件判断&#xff0c;还可以继承和重用模…

vue快速入门(五十七) 作用域插槽

注释很详细&#xff0c;直接上代码 上一篇 新增内容 作用域插槽实现表格删除数据 源码 App.vue <template><div id"app"><!-- 向子组件传值 --><MyTable :tableData"tableData"><!-- 接收子组件的传值&#xff0c;默认是对象格…

商超物联网~配置学生健康与安全

配置学生健康与安全示实验 作者&#xff1a;知孤云出岫 作者主页&#xff1a;点击这里 组网图形 图1 配置学生健康与安全示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 某学校由于重视学生的健康与安全&#xff0c;希望能够通过技术手段…

网络安全之静态路由

以下是一个静态路由的拓扑图 Aping通B&#xff0c;C可以ping通D。 路由器转发数据需要路由表&#xff0c;但仍可以Aping通B&#xff0c;C可以ping通D&#xff0c;是因为产生了直连路由&#xff1a;产生的条件有两个&#xff0c;接口有IP&#xff0c;接口双up(物理up&#xff…

使用应变计进行建筑物的健康监测

在建筑健康监测领域&#xff0c;应变计是一种至关重要的传感器&#xff0c;用于评估结构的安全和性能。特别是振弦式应变计&#xff0c;以其高精度和稳定性&#xff0c;成为监测建筑物健康状态的首选工具。本文将探讨振弦式应变计的工作原理、应用方法以及在建筑健康监测中的最…

STM32学习笔记--疑问篇

STM32学习笔记–疑问篇 GPIO是什么的缩写通用寄存器的缩写和全程 3.、这是什么的缩写 不同输出模式之间的差异 PB是GPIOB的缩写&#xff1f; 怎样知道端口应该设置成输入模式还是设置成输出模式

机器学习之基于Python多种混合模型的糖尿病预测

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 糖尿病是一种慢性代谢性疾病&#xff0c;其发病率在全球范围内逐年上升&#xff0c;已成为影响人类健…

OpenHarmony usb打开报错“usb fail error code = -3, error msg = LIBUSB_ERROR_ACCESS”

一、前言&#xff1a;最近公司项目需求&#xff0c;定位要求使用国产系统&#xff0c;国产系统无非就是 统信os &#xff0c;麒麟OS, 还有这两年比较热的 OpenHarmony。于是&#xff0c;老板要求公司产品适配OpenHarmony , 跟上时代步伐。 二、在开发中使用 usb 通讯时&#x…

明星中药企业系列洞察(二)丨百年御药同仁堂,为什么被称为我国最“硬”的老字号?

从最初的同仁堂药室、同仁堂药店到现在的北京同仁堂集团&#xff0c;经历了清王朝由强盛到衰弱、几次外敌入侵、军阀混战到新民主主义革命的历史沧桑&#xff0c;其所有制形式、企业性质、管理方式也都发生了根本性的变化&#xff0c;但同仁堂经历数代而不衰&#xff0c;在海内…