Linux开发_Linux下进程编程

414 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

本篇文章主要是介绍Linux下进程相关知识点,命令行控制进程的相关命令,介绍创建进程、管理进程相关函数。

任务 1: 进程编程

1.1 进程概念

./a.out //没有运行之前就是静态程序,运行之后就是一个进程

怎么区分进程?能够独立运行的程序,main。

每个进程都有自己唯一的PID号。

命令行可以通过ps命令获取后台进程的PID号。

示例:ps -e 查看后台全部进程

 #include <sys/types.h>
 #include <unistd.h>
 pid_t getpid(void); //获取进程PID
 pid_t getppid(void);

C语言代码方式获取PID

 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 int main(int argc,char **argv)
 {
 pid_t pid=getpid();
 printf("当前进程PID=%d ",pid);
 pid=getppid();
 printf("PPID=%d \n",pid);
 return 0;
 }

1.2 进程的信号

kill 命令功能:给程序发送信号。

查看所有支持的信号:kill -l

img

kill [-s signal|-p] [--] pid... kill -l [signal] :查看指定信号的帮助信息

发送信号的方式:

【1】kill <进程PID> //默认发送的进程终止信号,示例: #kill 348374

【2】kill -s <具体信号> <进程的PID> 示例: #kill -s SIGINT 7646

【3】kill -<具体信号> <进程的PID > 示例: # kill -SIGINT 7734

信号的捕获

 #include <signal.h>
 typedef void (*sighandler_t)(int);
 sighandler_t signal(int signum, sighandler_t han-dler);
 参数:
 int signum :要捕获的信号
 sighandler_t han-dler:函数指针

信号的捕获示例

 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 void sighandler(int sig)
 {
 printf("捕获的信号值=%d\n",sig);
 }
 int main(int argc,char **argv)
 {
 //将指定信号绑定到指定的函数上
 signal(SIGINT,sighandler); //2
 signal(SIGIO,sighandler); //29
 signal(SIGSYS,sighandler); //31
 while(1)
 {
 sleep(5);
 }
 return 0;
 }

Linux系统和windows这些系统属于非实时系统。 ucos\uclinux系统属于实时系统

【1】josb查看后台运行的程序作业代号。

【2】fg 1 将后台作业代号为1的程序切换到前台运行

【3】当程序在前台运行时,按下 ctrl+z 可以将程序放入后台,并且暂停运行。

【4】bg 1 将后台暂停的程序切换为运行状态

1.3 进程的创建

 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 int main(int argc,char **argv)
 {
 pid_t pid;
 pid=fork(); //创建一个新的进程
 if(pid==0) //子进程
 {
 printf("子进程pid=%d\n",getpid());
 }
 else if(pid>0) //父进程
 {
 printf("父进程pid=%d\n",getpid());
 }
 else //进程创建错误
 {
 printf("进程创建失败!\n");
 }
 return 0;
 }

fork 函数创建新进程本身属于一个拷贝的过程。继承功能!

进程的退出

 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 #include <stdlib.h>
 void print(void);
 int main(int argc,char **argv)
 {
 print();
 printf("main函数执行!");
 return 0;
 }
 ​
 void print(void)
 {
 printf("子函数执行!");
 //return; //终止函数,会将缓冲区里的数据输出
 //exit(0); //直接终止进程,会将缓冲区里的数据输出
 _exit(0); //强制终止进程,销毁缓冲区中的数据
 }

【1】查看僵尸进程:ps -aux

【2】查看系统的环境变量: env

【3】修改控制台终端的环境变量:export PS1='[\u@\h \W \t]$'

1.4 进程的执行

 #include <stdlib.h>
 int system(const char *command); // “ls -l” …..”cd”

接收命令的返回值:

 #include <stdio.h>
 int main(int argc,char **argv)
 {
 system("pwd >123.txt"); //获取脚本或者其他程序的返回值
 return 0;
 }

可变形参

 #include <stdio.h>
 void func(int data,...);
 int main(int argc,char **argv)
 {
 int data=888;
 func(data,123,456,789,100);
 return 0;
 }
 ​
 void func(int data,...)
 {
 int i=0;
 int *p=&data;
 for(i=0;i<5;i++)
 {
 printf("%d\n",*p++);
 }
 }

执行进程

 #include <stdio.h>
 #include <unistd.h>
 int main(int argc,char **argv)
 {
 execl("/bin/ls","ls","-l",NULL);
 printf("123\n");
 return 0;
 }
 ​
 #include <stdio.h>
 #include <unistd.h>
 int main(int argc,char **argv)
 {
 execlp("ls","ls","-l",NULL); //PATH=xxx:xxx:xxx:
 printf("123\n");
 return 0;
 ​
 }

管道:FIFO--->先入先出

通过命令行: mkfifo命令可以直接创建FIFO文件。

无名管道的FIFO文件不是实体文件,存在内存中的。

文件的方向: 即 fds[0]和读端相对应, fds[1]和写端相对应

有名管道的FIFO文件是实体文件,存在硬盘中的。

 #include <stdio.h>
 #include <unistd.h>
 /*
 #include <unistd.h>
 int pipe(int pipefd[2]);
 */
 int main(int argc,char **argv)
 {
 int pipefd[2];
 char buff[100];
 pipe(pipefd); //创建一个无名管道 [0]读 [1]写
 int pid=fork();
 if(pid) //父进程
 {
 while(1)
 {
 write(pipefd[1],"12345",6);
 sleep(1);
 }
 }
 ​
 else //子进程
 {
 while(1)
 {
 read(pipefd[0],buff,100);
 printf("buff=%s\n",buff);
 }
 }
 return 0;
 }

1.5 练习

【1】练习无名管道的通信,删除指定目录下的指定后缀的文件。

要求:子进程负责遍历文件,父进程就负责删除文件。

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 ​
 /*
 无名管道:
 fds[0] 表示读 
 fds[1] 表示写
 ​
 int dup2(int oldfd, int newfd); //实现文件描述符的重定向
 示例: dup2(fds[1],1); //将本程序的标准输出定义到管道的写端
 ​
 标准输入:0
 标准输出:1
 标准错误:2
 */
 int main(int argc,char **argv)
 {
     if(argc!=2)
     {
         printf("参数格式: ./app <传入一个文件>\n");
         exit(-1); //退出进程
     }
     
     int fds[2]; //定义了管道文件
     pipe(fds);  //创建无名管道文件
     char buff[100];
     char cmd[100];
     int status;
     int pid=fork();
     int len;
     if(pid==0)  //子进程,遍历目录,查找文件
     {
         write(fds[1],argv[1],strlen(argv[1])); //写入数据
         
         /*
         1. 定义一个二维数组,先将所有目录遍历完毕,将得到数据一次性写过去
         2. 遍历一个就写一个。(编写一个应答机制)
         */
     }
     else if(pid>0) //父进程,负责删除文件
     {
         len=read(fds[0],buff,100);
         buff[len]='\0';
         strcpy(cmd,"rm ");
         strcat(cmd,"-rf ");
         strcat(cmd,buff);
         printf("cmd=%s\n",cmd);
         system(cmd);    //执行最终的操作
         wait(&status); //随机等待一个子进程退出
     }
     else
     {
         printf("进程创建失败!\n");
         exit(-1);
     }
     return 0;
 }

【3】练习命名管道的通信,删除指定目录下的指定后缀的文件。

要求:子进程负责遍历文件,父进程就负责删除文件。

dup2(fd_pipe[1],1); //将子进程的标准输出重定向到管道的写端

【4】 (扩展) 通过命名管道实现本地聊天室,一个终端界面表示一个用户。

注明: 就一个.c程序,运行一个就是一个新的用户,每个进程之间通过命名管道通信。

(1) 每次运行程序需要输入用户名创建用户名。

(2) 每个新加入一个用户有欢迎提示,例如: 欢迎xxx加入xxx聊天室。

(3) 可以互相发送内容,发送内容时的格式: <用户名>: <实际内容>:<发送的时间>

(4) 可以显示在线人数。

(5) 一个用户发送内容,所有的用户都可以显示出来。

(6) 通过一个文件保存聊天记录。