Linux进程编程记录

本文详细介绍了进程的相关概念,包括程序与进程的区别、进程查看、进程标识符、父进程与子进程的关系。通过C语言展示了fork函数创建进程的用法,探讨了vfork的特性,以及进程退出的各种方式。同时,讲解了如何通过wait函数等待子进程退出,以及exec族函数在进程间的执行。最后,提到了system函数和popen函数在执行命令和读取输出方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程相关概念

1.什么是程序,什么是进程,有什么区别

程序是静态的概念,gcc  xxx.c -o pro,磁盘中生成的pro文件叫程序

进程是程序的一次的活动,只要程序跑,系统中就多了一个进程

2.如何查看进程

ps 或ps -aux|grep  要查找的进程

3.什么是进程标识符

每个进程都有一个非负整数表示唯一ID,叫做pid,有点像身份证

pid=0:称为交换进程,作用:进程调度

pid=1:init进程,作用:系统初始化

调用getpid()获取自身进程标识符,getppid()获取获取父进程标识符

4.什么是父进程,什么是子进程

进程A创建了进程B,A就是父进程,B就是子进程

5.C语言的存储空间是如何分配的(自己画的,有点丑)

二、创建进程fork函数使用

           fork函数调用成功,返回两次,返回值为0,代表当前进程是子进程,非负数为父进程

           创建子进程的目的:复制父进程,在父进程等待客户端的服务请求,当这种请求到达时,父进程调用fork,让子进程去处理。

           通俗点说就是:你爸让你去买烟,让你去干活

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(){
        //pid_t getpid(void);//获取自身的进程标识符
        //pid_t getppid(void);//获取父进程的进程标识符
        pid_t pid;//pid_t类似一个类型,就像int型一样,int型定义的变量都是整型的,pid_t定义的类型都是进程号类型。>用来接收进程号的返回值
        pid_t pid2;
        pid=getpid();
        //pid_t fork(void);//创建进程,fork函数调用成功,返回两次,返回值为0,代表当前进程是子进程,返回值为非负数,代表当前进程为父进程
        pid2=fork();
        if(pid2 > 0){
                printf("这是父进程! pid=%d,pid2=%d\n",pid,pid2);
        }
        else if(pid2 == 0){
                printf("这是子进程! pid=%d,pid2=%d\n",pid,pid2);
        }
        return 0;

}

三、进程创建发生了什么事?

发生了复制,就是把代码段啊,数据段啊这些都统统复制了一遍,新进程就去执行这些

四、创建新进程实际应用案例

不输入指定的数字就一直等待数字的输入

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
pid_t pid;
int data;
int main(){
        while(1){
        printf("please input data:");
        scanf("%d",&data);
                if(data==1){
                        pid=fork();
                        if(pid > 0){
                        }
                        else if(pid==0){
                                while(1){
                                        printf("do net request!,pid=%d\n",getpid());
                                        sleep(3);
                                }
                        }
                }
                else{
                        printf("waiting insert data......\n");
                }
        }
        return 0;
}

运行结果:

五、vfork创建进程

vfork与fork的区别:

1.vfork直接使用父进程的存储空间,不拷贝

2.vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行

int main(){
        int cnt=0;
        pid_t pid;
        pid_t repid;
        pid=getpid();
        repid=vfork();
        if(repid > 0){
                while(1){
                        printf("cnt=%d\n",cnt);
                        printf("this is father pid,repid=%d\n",repid);
                        sleep(1);
                }
        }
        else if(repid == 0){
                while(1){
                        printf("this is child pid,repid=%d\n",repid);
                        sleep(1);
                        cnt++;
                        if(cnt==2){

                                exit(0);
                        }
                }
        }
        return 0;
}

运行结果:

六、进程退出

正常退出:

1.main函数调用return

2.进程调用exit(),标准C库

3.进程调用_exit()或者_Exit(),系统调用

4.进程最后一个线程返回

5.最后一个线程调用pthread_exit

异常退出

1.调用abort

2.当进程收到某些信号时,如ctrl+c

3.最后一个线程对取消(cancellation)请求作出响应

注意:不管进程如何终止,最后都会执行内核中的同一段代码,这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。

七、父进程等待子进程退出

pid_t wait(int *status);

status参数:整型指针

非空:子进程退出状态放在它所指向的地址中

空:不关心退出状态

int main(){
        pid_t pid;
        pid_t repid;
        int cnt=0;
        int status;
        pid=getpid();
        repid=fork();
                if(repid > 0){
                        wait(&status);//等待子进程退出
                        //子进程正常退出,WEXITSTATUS
                        printf("status=%d\n",WEXITSTATUS(status));//把终止的子进程通知给父进程
                        while(1){
                                printf("this is father pid,repid=%d\n",repid);
                                sleep(1);
                        }
                }
                else if(repid == 0){
                        while(1){
                                printf("this is child pid,repid=%d\n",repid);
                                sleep(1);
                                cnt++;
                                if(cnt==5){
                                        printf("cnt=%d\n",cnt);
                                        exit(5);
                                }
                        }
                }
        return 0;
}

八、exec族群

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

int main(){

        //int execl(const char *path, const char *arg, .../* (char  *) NULL */);
/*      path:可执行文件的路径名字
        arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
        file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件
        exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
        l : 使用参数列表
        p:使用文件名,并从PATH环境进行寻找可执行文件
        v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
        e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量

        exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。 
*/

        printf("before execl\n");
        if(execl("/bin/ls","ls",NULL,NULL) == -1)
        {
                printf("execl failed!\n");
                perror("why");
        }
                printf("after execl\n");

        return 0;
}
int main(){

        //int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
        printf("before execl\n");
        if(execlp("ls","ls","-l",NULL) == -1)
        {
                printf("execl failed!\n");
                perror("why");
        }
                printf("after execl\n");

        return 0;
}
int main(){

        //int execv(const char *path, char *const argv[]);      

        char* argv[]={"ls",NULL,NULL};
        if(execv("/bin/ls",argv) == -1)
        {
                printf("execl failed!\n");
                perror("why");
        }
                printf("after execl\n");

        return 0;
}

 

int main(){

        // int execvp(const char *file, char *const argv[]);

        char* argv[]={"ls","-l",NULL};
        if(execvp("ls",argv) == -1)
        {
                printf("execl failed!\n");
                perror("why");
        }
                printf("after execl\n");

        return 0;
}

九、exec与fork相结合

int main(){
        pid_t pid;
        pid_t repid;
        int data;
        while(1){
                printf("please input a number:");
                scanf("%d",&data);
                if(data==1){
                        repid=fork();//创建进程
                        if(repid > 0){
                                wait(NULL);
                        }
                         if(repid == 0){

                                execl("./changeNumToFile.out","changeNumToFile.c","changeNum.c",NULL);
                                exit(0);

                                }
                        }
                else{
                        printf("waiting!\n");
                }
        }
        return 0;
}
//changeNumToFile.c
int main(int argc,char* argv[]){

        int fd;
        char* readBuf;
        //int open(const char *pathname, int flags);

        fd=open("./changeNum.c",O_RDWR);//打开文件
        int size=lseek(fd,0,SEEK_END);
        lseek(fd,0,SEEK_SET);
        //ssize_t read(int fd, void *buf, size_t count);
        readBuf=(char*)malloc(sizeof(char)*size+8);
        int n_read=read(fd,readBuf,size);
        char* p=strstr(readBuf,"ouliang=");
        if(p==NULL){
                printf("not fingd\n");
        }
        else{
                p=p+strlen("ouliang=");
                *p='5';
                lseek(fd,0,SEEK_SET);
                int n_write=write(fd,readBuf,size);
        }
        close(fd);
        return 0;
}

 

//changeNum
dugad=100;
ouliang=3;
aisi=120;

运行结果:

十、system函数

int main(){
        pid_t pid;
        pid_t repid;
        int data;
        while(1){
                printf("please input a number:");
                scanf("%d",&data);
                if(data==1){
                        repid=fork();//创建进程
                        if(repid > 0){
                                wait(NULL);
                        }
                         if(repid == 0){

                                //execl("./changeNumToFile.out","changeNumToFile.c","changeNum.c",NULL);
                                system("./changeNumToFile.out");//执行完该函数后,还会执行后面的函数
                                exit(0);
                                }
                        }
                else{
                        printf("waiting!\n");
                }
        }
        return 0;

十一、popen函数

#include <stdio.h>
#include <stdlib.h>
 //      FILE *popen(const char *command, const char *type);
//       FILE *fopen(const char *path, const char *mode);
//      size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int main(){

//      system("ls");
        FILE* fp;
        char ret[1024];
        fp=popen("ls -l","r");
        int nread=fread(ret,1,1024,fp);

        if(nread != -1){
                printf("read sucess!\n");
                printf("return nread=%d,read datas=\n%s\n",nread,ret);
        }
        else{
                printf("no read datas\n");
        }
        return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值