Linux-C语言编程-Day-1

进程概念

 进程是程序在计算机上执行一次的过程,也就是一个执行中的程序,进程是一个独立的逻辑控制流,独占处理器,相当于工人和机器,进程具有私有的地址空间,独占存储器系统,相当于工厂;进程的本质是程序在地址空间中按照代码逻辑控制流执行的过程,同时进程是资源分配的最小单位;

进程和程序的区别

 进程是动态的,并且具有生命周期,并且一个进程只能对应于一个程序;相反,程序是动态的指令集合,一个程序可以对应于多个进程;

进程的状态

 就绪:Ready,当进程获得出CPU以外的所有的必要的资源时,进程进入就绪状态,也就是说当进程得到CPU就可以立即运行;
 运行:Runing,进程正在占据CPU资源;
 阻塞(Blocked):进程犹豫等待某个事件发生而无法执行时,进程被迫放弃CPU执行资源;

进程的创建
进程的查看

Windows可以使用tasklist 例如:tasklist / F1 “PID eq 进程PID”
Linux底下可以使用ps命令进行查看,ps命令的相关选项:
user:表示进程所属的用户;
PID:表示进程ID;
ppid:表示父进程ID;
%CPU:表示CPU占有率;
%mem:表示内存占有率;
VSZ:表示进程虚拟大小;
RSS:表示常驻内存,也就是内存中页面的数量;
tty:表示进程使用的终端;
stat:表示进程的状态;
start:表示启动进程的时间;
TIME:表示进程消耗CPU的时间;
command:表示打开进程的命令和参数;
 进程状态标识符:
  D:表示不可中断进程,Uninterruptible;
  R:表示正在运行,或者在队列中的进程;
  S:处于休眠状态;
  T:进程处于停止或者被追踪状态;
  Z:僵尸进程;
  W:表示进入内存交换,从内核2.6以后开始失效;
  X:表示死掉的进程;
  <:表示高优先级;
  n:表示低优先级;
  s:表示包含子进程;
  +:表示位于后台的进程组;
 查看某个具体的进程:
ps -p pidps -C在命令行进行查看;同样的还可以使用pstree进行查看,但是可能需要安装yum install psmisc -y`;同样的的还可以使用top命令动态的查看系统进程;

进程的杀死

 windows:task kill /F /PID 或者task kill /F /IM 程序名
linuxkill 进程标识PID
 与进程相关的文件一般在/proc/底下,通常是进程id作为目录名的文件;

进程的操作

进程的标识通常使用pid来完成,获取当前进程的id使用函数pid_t getpid();获取当前进程父进程的ID使用函数pid_t getppid();

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

int main(){
    printf("PID:%dPPID:%d\n",getpid(),getppid());//分别用于获得当前进程ID和父进程ID;
    for(;;);
}
关于进程的创建
fork()函数

 函数失败时返回值是-1,返回值为0表示子进程逻辑控制流,如果返回值为其他,表示父进程控制流;
 函数的特点:
  1、调用一次,返回两次;
  2、相同但是具有独立的地址空间;
  3、可以并发执行;
  4、这个函数的本质是函数堆栈数据,text文本的复制;
函数的本质是父进程函数相关数据的复制,然后分叉出另一个函数;

#include <stdio.h>
#include <unistd.h>
int main(){
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    pid_t pid = fork();
    fork();
    if(pid == 0){// child
        printf("this is child\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
    }else{
        printf("this is father\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
    }
    for(;;);
}

 子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
fork02.c:这个函数是用来构建子进程,用来输出一些值;

#include <stdio.h>
#include <unistd.h>
int i = 100;
int main(){
    int j=100;
    pid_t pid = fork();
    if(pid == 0){// child
        int k;
        for(k=0;k<10000;k++)
            printf("this is childi%d\t j%d\n",++i,++j);
    }else{
        int k;
        for(k=0;k<10000;k++)
            printf("this is fatheri%d\t j%d\n",--i,--j);
    }
}

fork03.c:这个函数父进程在增加变量的值,子进程在减小函数的值,用来模拟两个进程的运行情况;

#include <stdio.h>
#include <unistd.h>
int i = 100;
int main(){
    int j=100;
    FILE* fd = fopen("./test","w+");
    pid_t pid = fork();
    if(pid == 0){// child
        int k;
        for(k=0;k<10000;k++)
            fprintf(fd,"this is childi%d\t j%d\n",++i,++j);
    }else{
        int k;
        for(k=0;k<10000;k++)
            fprintf(fd,"this is fatheri%d\t j%d\n",--i,--j);
    }
}
exec函数簇
char **environ;  
int execl (const char *path, const char *arg0, ..., (char*)0);  
int execlp(const char *file, const char *arg0, ..., (char*)0);  
int execle(const char *path, const char *arg0, ..., (char*)0, char *const envp[]);  
int execv (const char *path, char *const argv[]);  
int execvp(cosnt char *file, char *const argv[]);  
int execve(const char *path, char *const argv[], char *const envp[]);

execl.c

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

extern char ** environ;

int main(int argc,char **argv){
    execl("/bin/ps","ps","-a","-o","pid,ppid,cmd,stat",0);
    return 0;
}

execle.c

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

extern char **environ;

int main(int argc,char **argv){
    execle("/bin/ps","ps","-a","-o","pid,ppid,cmd,stat",0,environ);
    return 0;
}

execlp.c

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

int main(int argc,char **argv){
    execlp("ps","ps","-a","-o","pid,ppid,cmd,stat",0);
    return 0;
}

execv.c

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

int main(){
    char *args[]={"ps","-a","-o","pid,ppid,cmd,stat",0};
    execv("/bin/ps",args);
    return 0;
}

execve.c

#include <stdio.h>
#include <unistd.h>
extern char **environ;

int main(){
    char *args[]={"ps","-a","-o","pid,ppid,cmd,stat",0};
    execve("/bin/ps",args,environ);
    return 0;
}

execvp.c

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

int main(){
    char *argv[] = {"ps","-a","-o","pid,ppid,cmd,stat",0};
    execvp("ps",argv);
    return 0;
}

函数命名的规律组总结
v:表示第二个参数是数组;
l:第二个参数之后是变参;
p:第一个参数是文件名;
e:最后一个参数是环境变量;
常见的字符串数组函数
execv(),execvp(),execve()
可变参数函数
execle(),execlp(),execl();
exec.c函数:
 exec函数簇函数的返回值,-1表示失败,执行成功时,是不返回任何值的,这些函数具有以下特点:一次调用,失败返回;改朝换代,取而代之;但是函数的PID是不会变化的,变化的是程序地址空间的内容,exec函数簇函数的本质是覆盖原有函数,执行新的函数;

system(shell字符串)

 这个函数是系统函数int system(shell 字符串或者命令);函数的返回值为-1时,表示失败;函数的返回值是127时,表示无法启动shell;其它返回值用于表示函数的退出码;系统调用函数一次调用,一次返回;这个函数本质上是在执行shell命令;
*system.c

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

int main(int argc,char** argv){
    printf("PID:%d\n",getpid());    
    system("sleep 3&");
    printf("PID:%d\n",getpid());    
}
进程的结束

 对于returnexit来说,函数的执行属于寿终正寝,并且自己能够了结后事。_exit()函数属于自杀的情况,但是没有料理后事。abort()函数属于意外的死亡,也没有料理后事;信号终止属于他杀;料理后事表示的意思是程序结束以后,相关堆栈资源的回收工作;
main()函数return 0 是语言级别的退出,使用这种情况的退出,函数仍然需要调用exit(0)函数,exit(0)是函数级别的退出;
exit(0),表示释放所有的静态的全局对象,缓存,关掉所有的IO通道,然后终止程序;abort()会直接终止程序,但是不会释放任何资源;
exit(0)函数在调用_exit()系统调用之前要检查文件的打开情况,吧文件缓冲区中的内容写回文件,清理IO缓冲,exit(0)是标准的C函数;
_exit()不做清理IO缓冲函数,_exit()Linux系统调用;
 main函数退出:
main.c

#include <stdio.h>
#include <unistd.h>
int main(){
    printf("PID:%d,PPID:%d\n",getpid(),getppid());

    return 100;
}

exit函数退出
exit函数一般用在main函数以外的函数退出

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    exit(EXIT_FAILURE);
    abort();
}

_exit函数一般用来结束子进程
这个函数暂时没有说明
abort()函数一般用来异常退出

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    abort();
}

还有一种方式–信号终止
pause.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void test(int sig){
    printf("revc a signal%d",sig);
}

int main(){
    signal(SIGINT,test);
    printf("before pause\n");
    pause();
    printf("after pause\n");
}
进程的停止

int sleep(unsigned int secs)函数 ,sece用于表示休眠的秒数,如果指定为-1表示永久休眠,函数的返回值是未休眠的秒数;如果没有信号中断,休眠指定的秒数返回0,否则马上返回未休眠的秒数;

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <strings.h>
int main(){
    int i = 0;
    for(;;){
        time_t t;
        time(&t);
        struct tm* ptm =  gmtime(&t);
        char buf[BUFSIZ];
        bzero(buf,BUFSIZ);
        strftime(buf,BUFSIZ,"%P %T",ptm);
        printf("\r%s",buf);
        fflush(stdout);
        sleep(1);
    }
}

int pause()函数返回值一定是-1,如果函数没有处理信号,直接中断,执行默认的信号处理,程序后续代码不再执行。如果程序存在信号处理,执行处理信号后,执行后续代码。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void test(int sig){
    printf("revc a signal%d",sig);
}
int main(){
    signal(SIGINT,test);
    printf("before pause\n");
    pause();
    printf("after pause\n");
}

pid_t wait(int * status):函数等价于pid_t waitpid(-1,status,0);这个函数的参数包括:pid:小于-1时,表示的是等待进程组为pid的所有进程,-1:表示等待任何子进程;0:表示等待同组的进程;大于0:表示等待进程为pid的子进程;
status:参数的含义:
  正常结束,WIFEXITED(status)参数为0时,表示的是正常结束任何子进程,0表示的是非正常结束子进程;WEXITSTATUS()表示取得子进程exit()返回的结束代码,一般会先用WIFEXITED来判断是否正常结束才是用这个宏定义;
  异常结束:WIFSIGNALED(ststus)非0值表示异常结束子进程,0表示非异常结束子进程;WTERMSIG(status),取得子进程因信号而终止的信号代码,一般先会用WIFSIGNALED来判断后才能使用宏;
  暂停:WIFSTOPPED(status),非0值表示暂停结束子进程,0表示暂停结束子进程;WSTOPSIG(status),取得引发子进程暂停的信号代码,一般先用
WIFSTOPPED来判断后才能使用此宏;
option,选项WNOHANG,若子进程没有结束,返回0,不予等待。若子进程结束,返回该子进程的ID;WUNTRACED,若子进程进入暂停状态,则马上返回,但子进程的结束状态不予理会。
 返回值,-1表示失败;其他值表示等待的PID;
wait.c:

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

void handler(int sig){
    pid_t cpid = wait(NULL);
    printf("child %d exit",cpid);
}

int main(){
    signal(SIGCHLD,handler);
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    pid_t pid = fork();
    if(pid == 0){// child
        sleep(2);
        printf("this is child\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
    }else{
        printf("this is father\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
    }
}

wait02.c:

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

void handler(int sig){
    int status;
    pid_t cpid = wait(&status);
    if(WIFEXITED(status)){
        printf("child exit by %d\n",WEXITSTATUS(status));
    }   
    if(WIFSIGNALED(status)){
        printf("child exit by signal %d\n",WTERMSIG(status));
    }
    printf("child %d exit\n",cpid);
}

int main(){
    signal(SIGCHLD,handler);
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    pid_t pid = fork();
    if(pid == 0){// child
        sleep(2);
        printf("this is child\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
        //exit(0);
    }else{
        printf("this is father\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
        printf("leave:%d\n",sleep(5));
        //exit(200);
    }
    for(;;);
}
孤儿进程与僵尸进程

 孤儿进程:父进程先于子进程退出,init进程作为新的父进程,但是对于系统无害,init进程会回收这些系统资源;
 僵尸进程:子进程退出,父进程没有获得子进程的状态信息,可以通过调用wait(status)或者调用waitpid函数来实现;
waitpid.c

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

int main(){
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    pid_t pid = fork();
    if(pid == 0){// child
        sleep(2);
        printf("this is child\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
        //exit(0);
    }else{
        printf("this is father\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
        printf("pid:%d exit\n",waitpid(pid,NULL,0));
    }
}

zomble.c:

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
void handle(int sig){
    //wait(NULL);
    printf("this is child exit %d",sig);
}
int main(){
    signal(SIGCHLD,handle);
    printf("PID:%d,PPID:%d\n",getpid(),getppid());
    pid_t pid = fork();
    if(pid == 0){// child
        printf("this is child\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
    }else{
        printf("this is father\n");
        printf("res:%d,PID:%d,PPID:%d\n",pid,getpid(),getppid());
        for(;;);
    }
}

一个模拟简单shell的程序:
shell.c

//这个程序是一个简单的shell程序,可以用于执行shell命令中不带有参数选项的命令;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

void handle(int sig){
    wait(NULL);
}
int main(){
    printf("welcome to sim shell\n");
    //
    signal(SIGCHLD,handle);

    for(;;){
        printf(">");
        fflush(stdout);
        char buf[BUFSIZ];
        bzero(buf,BUFSIZ);
        fgets(buf,BUFSIZ,stdin);
            size_t n = strlen(buf);
        if(buf[n-1] == '\n'){
            buf[n-1] = '\0';
        }       
        if(strcmp(buf,"quit")==0)
            break;
        //system(buf);
        char* argv[128];
        bzero(argv,128);
        char* p = buf;
        int index = 0;
        char* temp = NULL;
        do{ 
            temp =strtok(p," ");
            p = NULL;
            argv[index++] = temp;
        }while(temp != NULL);
        if(fork() == 0){
            execvp(argv[0],argv);   
        }
        //sleep(-1);
        pause();
    }   

    printf("sim shell exit\n");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值