Linux 二十一章

news2024/11/23 15:53:29

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

❤️‍🔥专栏系列:线性代数,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、页表等),页表没有映射物理内存

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

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

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

相关文章

1000公里清晰可见,光纤资源管理新方案——记录与查询

01传统模式光纤资源管理下 记录难 不止有手工记录与CAD记录&#xff0c;还有Excel、PPT、Visio、JPG、PNG、老师傅经验记... 查询难 需要大量翻查CAD、Excel、PPT、Visio、JPG、PNG才能得到完整光缆的信息&#xff0c;可是老师傅记录怎么查询&…

小心电子合同这个坑:PS章

近期&#xff0c;我发现网上有很多教程教大家如何自己动手用PS制作电子章&#xff0c; 看似方便&#xff0c;实则危机四伏&#xff01; 通过PS技术&#xff0c;你可以生成任何一家公司的印章&#xff0c; 用以冒充电子章&#xff0c;或打印出来冒充实体章。 甚至还能进行做旧…

CCD光学触摸屏中应用到的电容式触摸芯片

CCD光学触摸屏是利用CCD光学触摸技术打破原有触摸技术的瓶颈&#xff0c;从准确率、反应速度和寿命方面大幅度提高&#xff0c;安装在顶部左右角的两个CCD摄像头可以精准地检测出多个手指位置&#xff0c;不仅可以单击、拖拉&#xff0c;还可以自由旋转和放大图片&#xff0c;这…

相关性分析

目录 1.交叉功率谱 2. 相关系数 1.交叉功率谱 % 生成两个信号 t 0:0.001:100; x sin(2*pi*1*t)sin(2*pi*2*t); y sin(2*pi*t )sin(2*pi*2*t); % 计算交叉功率谱密度 [Pxy, F] cpsd(x, y, [], [], [], 1/(t(2)-t(1))); % 使用正确的采样频率 % 绘制交叉功率谱密度图 …

参数服务器

参数服务器在ROS中主要用于实现不同节点之间的数据共享。参数服务器相当于是独立于所有节点的一个公共容器&#xff0c;可以将数据存储在该容器中&#xff0c;被不同的节点调用&#xff0c;当然不同的节点也可以往其中存储数据。 参数服务器&#xff0c;一般适用于存在数据共享…

linux进入单用户模式指引

文章目录 引言I 通过GRUB进入单用户模式1.1 倒计时界面的操作1.2 GRUB1.3 内核参数编辑界面1.4 更多内核参数编辑界面II 预备知识:Linux用户模式引言 应用场景: root密码重置: 用passwd命令修改root修复登录相关的配置:/etc/pam.d/login 和 /etc/pam.d/sshd 案例:Centos6进…

Dropout作为贝叶斯近似: 表示深度学习中的模型不确定性

摘要 深度学习工具在应用机器学习领域受到了极大的关注。然而&#xff0c;这些用于回归和分类的工具并没有捕捉到模型的不确定性。相比之下&#xff0c;贝叶斯模型提供了一个基于数学的框架来推理模型的不确定性&#xff0c;但通常会带来令人望而却步的计算成本。本文提出了一…

vue2实现右键菜单功能——vue-diy-rightmenu——基础积累

五一之前遇到一个需求&#xff0c;就是关于要实现自定义右键菜单的功能&#xff0c;普通的右键展示的菜单有【返回/前进/重新加载/另存为】等&#xff0c;希望实现的效果就是右键出现自定义的菜单&#xff0c;比如【编辑/删除/新增】等。 遇到这种的需求&#xff0c;可以直接去…

Leetcode—1991. 找到数组的中间位置【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—1991. 找到数组的中间位置 实现代码 class Solution { public:int findMiddleIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size();…

信息安全-隐写术到可逆信息隐藏

进入二十一世纪以来&#xff0c;通信技术飞速发展&#xff0c;使得多媒体被广泛用于传输数据&#xff0c;尤其是物联网上。通常&#xff0c;我们的多媒体传输发生在不安全的网络通道上。特别是&#xff0c;互联网在交换数字媒体和个人、私人公司、机构、政府使用这些多媒体数据…

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

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

春秋云镜 CVE-2022-4230

靶标介绍&#xff1a; WP Statistics WordPress 插件13.2.9之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (admin) 的用户可以使用受影响的功能&#xff0c;但是该插件有一个设置允许低权限用户…

thinkadmin table列表页点击直接修改用户金额(其他内容都可以)

需要修改用户余额时 点击余额区域 可以手动输入金额 输入后调用api接口自动刷新 html代码 // 初始化表格组件$(#NewsTable).layTable({even: true, height: full,sort: {field: id, type: desc},where: {type: {$type|default="index"}},cols: [[{checkbox: true,…

计算机网络【应用层】邮件和DNS

文章目录 电子邮件DNSDNS提供的服务&#xff1a;域名分级域名解析流程DNS资源记录DNS服务器类型 电子邮件 使用SMTP协议发送邮件之前&#xff0c;需要将二进制多媒体数据编码为ASCII码SMTP一般不使用中间邮件服务器发送邮件&#xff0c;如果收件服务器没开机&#xff0c;那么会…

ICode国际青少年编程竞赛- Python-1级训练场-综合训练1

ICode国际青少年编程竞赛- Python-1级训练场-综合训练1 1、 Spaceship.turnLeft() for i in range(2):Spaceship.turnLeft()Spaceship.step(3) Dev.step(-1) Spaceship.step(4) Spaceship.turnLeft() Spaceship.step(3)2、 Spaceship.step() Spaceship.turnLeft() Spaceship.…

V23 中的新功能:LEADTOOLS 展示了它的 EXCEL-lence

LEADTOOLS (Lead Technology)由Moe Daher and Rich Little创建于1990年&#xff0c;其总部设在北卡罗来纳州夏洛特。LEAD的建立是为了使Daher先生在数码图象与压缩技术领域的发明面向市场。在过去超过30年的发展历程中&#xff0c;LEAD以其在全世界主要国家中占有的市场领导地位…

CH32V 系列 MCU IAP 使用函数形式通过传参形式灵活指定APP跳转地址

参考: CH32V 系列 MCU IAP 升级跳转方法 CH32V103 的 IAP 问题&#xff08;跳转及中断向量表重定位&#xff09; 1. 沁恒的RISC-V内核MCU的IAP跳转示例程序简要分析 沁恒的RISC-V内核的MCU比如CH32V203、CH32V307等系列的EVT包中IAP升级的示例程序中都是通过使能软件中断之后&…

ABB RobotStudio学习记录(一)新建工作站

RobotStudio新建工作站 最近遇到 虚拟示教器和 Rapid 代码不能控制 视图中机械臂的问题。以下是解决方法。 名称版本Robot Studio6.08 新建一个”空工作站“&#xff1b; 在目标位置新建一个目标文件夹 C:\solution\test&#xff0c;用以后续存放该工作站&#xff08;通常路径…

CAXA 3D实体设计2024:塑造未来的创新引擎

在数字化时代的浪潮中&#xff0c;3D CAD实体建模设计正成为推动工业创新的核心动力。CAXA 3D实体设计2024&#xff0c;以其卓越的性能和丰富的功能&#xff0c;为企业和个人用户带来了前所未有的设计体验。 CAXA 3D实体设计2024不仅拥有直观易用的界面&#xff0c;还配备了强…

java-函数式编程-jdk

背景 函数式接口很简单&#xff0c;但是不是每一个函数式接口都需要我们自己来写jdk 根据 有无参数&#xff0c;有无返回值&#xff0c;参数的个数和类型&#xff0c;返回值的类型 提前定义了一些通用的函数式接口 IntPredicate 参数&#xff1a;有一个&#xff0c;类型是int类…