Linux进程探秘:深入理解进程管理、通信与调度机制

0.进程巫师

函数名称参数返回值用法
fork父进程返回子进程ID,子进程返回0pid_t fork(void);
exec 系列const char *path, char *const argv[]-1(失败), 不返回(成功)int execv(const char *path, char *const argv[]);
waitpidpid_t pid, int *status, int options子进程IDpid_t waitpid(pid_t pid, int *status, int options);
exitint statusvoid exit(int status);
getpid进程IDpid_t getpid(void);
getppid父进程IDpid_t getppid(void);
pipeint pipe(int pipefd[2]);0(成功), -1(失败)创建一个管道,pipefd[0] 用于读,pipefd[1] 用于写
dupint oldfd新文件描述符int dup(int oldfd);
dup2int oldfd, int newfd新文件描述符int dup2(int oldfd, int newfd);
closeint fd0(成功), -1(失败)关闭文件描述符
killpid_t pid, int sig0(成功), -1(失败)向进程发送信号
signalint signum, void (*handler)(int)先前的信号处理程序void (*signal(int signum, void (*handler)(int)))(int);
sigactionint signum, const struct sigaction *act, struct sigaction *oldact0(成功), -1(失败)安装、改变或检索信号处理程序
popenconst char *command, const char *typeFILE *打开一个管道并返回一个文件流,用于读取或写入子进程的标准输入/输出
pcloseFILE *stream终止进程并关闭文件流int pclose(FILE *stream);
execlconst char *path, const char *arg, ...-1(失败), 不返回(成功)执行一个文件
execleconst char *path, const char *arg, ..., char *const envp[]-1(失败), 不返回(成功)执行一个文件,并提供新的环境变量
execvpconst char *file, char *const argv[]-1(失败), 不返回(成功)通过搜索 PATH 执行一个文件
vfork父进程返回子进程ID,子进程返回0pid_t vfork(void);
waitint *status子进程IDpid_t wait(int *status);

1. 进程基础概念

a. 什么是进程?
- 进程是计算机中运行的程序的实例。它包括了程序执行时所需的代码、数据以及系统资源,每个进程都有其独立的内存空间。

b. 进程的状态(运行、就绪、阻塞等)
- 运行(Running): 进程正在执行。
- 就绪(Ready): 进程已准备好执行,等待分配CPU。
- 阻塞(Blocked): 进程等待某个事件的完成,如等待用户输入或等待文件I/O。

c. 进程的标识符(PID)
- 每个进程都有一个唯一的标识符,称为PID。可以使用ps命令查看正在运行的进程及其PID。

   ps aux

d. 父进程和子进程
- 进程可以通过fork系统调用创建一个新的进程。新进程称为子进程,而调用fork的进程称为父进程。

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

      int main() {
          pid_t child_pid = fork();                            

          if (child_pid == 0) {
              // 子进程执行的代码
              printf("This is the child process\n");  
          } else if (child_pid > 0) {  
              // 父进程执行的代码
              printf("This is the parent process\n");  
          } else {
              // fork失败
              perror("fork failed");
              return 1;
          }

          return 0;
      }

2. 进程的创建和终止

a. 进程的创建(fork、exec等)
- 进程的创建通常使用fork系统调用。子进程可以通过exec族函数加载新的程序。

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

   int main() {
       pid_t child_pid = fork();          

       if (child_pid == 0) {
           // 子进程执行的代码
           execlp("/bin/ls", "ls", NULL); // 以ls程序替换子进程
       } else if (child_pid > 0) {
           // 父进程执行的代码
           wait(NULL); // 等待子进程结束
           printf("Parent process finished\n");
       } else {
           perror("fork failed");
           return 1;
       }

       return 0;
   }

b. 进程的终止(exit)
- 进程可以通过exit系统调用正常终止。

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

     int main() {
         printf("This is a process\n");     
         exit(0); // 正常退出
     }

c. 僵尸进程和孤儿进程
- 僵尸进程是已经终止但父进程尚未回收的进程。孤儿进程是父进程已经终止而子进程仍在运行的进程。

3. 进程调度

a. 调度算法(先来先服务,短作业优先等)
- 调度算法决定了系统中不同进程之间的优先级和执行顺序。

b. nice值和优先级
- nice命令用于调整进程的优先级。

      nice -n 10 ./my_process

c. 进程调度器(如CFS)
- CFS(完全公平调度器)是Linux中的一个调度算法,通过时间片和进程优先级来平衡系统中运行的进程。

      cat /proc/sys/kernel/sched_child_runs_first      

5. 进程的优先级和调度策略

a. nice值和进程优先级
- nice值用于调整进程的优先级,取值范围通常为-20(最高优先级)到19(最低优先级)。

     nice -n 10 ./my_process

b. 调度策略(SCHED_FIFO、SCHED_RR等)
- Linux支持不同的调度策略,如先来先服务(SCHED_FIFO)、轮转调度(SCHED_RR)等。

     #include <stdio.h>
     #include <sched.h>     

     int main() {
         struct sched_param param;
         param.sched_priority = 50; // 优先级设置为50

         if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
             perror("Error setting scheduler");
             return 1;
         }

         // 进程的其他代码

         return 0;
     }

6. 进程的资源限制

a. 进程资源限制的设置(ulimit等)
- 使用ulimit命令可以设置进程的资源限制,如文件打开数、CPU时间等。

     ulimit -n 1000

b. 资源限制的影响
- 设置资源限制可以防止进程占用过多系统资源,导致系统不稳定.

7. 进程间通信(IPC)

方法描述使用场景优点缺点
文件锁(Flock)利用文件锁机制,通过系统调用 flock 来实现,进程对文件的操作会受到文件锁的限制。多进程读写同一文件时的资源互斥简单易用,适用于文件级别的进程同步只能在本地文件系统上使用,不能跨网络
信号(Signal)除了上文提到的通知外,还可以通过信号进行自定义通信,使用 killraise 发送信号。需要快速的事件通知轻量级,适用于简单的进程间通信信号不支持传递大量数据,容易被中断或丢失数据
套接字(Socket)使用套接字进行通信,可以通过本地套接字或网络套接字实现进程间通信。跨网络或本地通信强大而灵活,适用于不同主机间的通信相对较为复杂,需要网络编程知识
共享文件映射(Memory-Mapped Files)将文件映射到内存中,多个进程可同时读写该文件,实现共享内存的效果。需要共享大量数据高性能,适用于需要大量数据交换的场景需要谨慎处理同步和互斥问题,不适用于大规模并发
RPC(Remote Procedure Call)调用远程进程的过程,通过网络协议进行通信,实现跨网络的进程通信。跨网络通信适用于分布式系统,实现进程间远程调用需要网络编程知识,相对较为复杂
消费者-生产者队列(Message Queue)通过消息队列传递数据,可以实现多对多通信,进程通过队列进行数据交换。异步通信,需要解耦生产者和消费者适用于生产者和消费者模型,支持异步通信性能相对较低,需要处理消息格式和序列化问题

a. 管道(Pipe)
- 管道是一种进程间通信的机制,通过pipe系统调用创建。

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

      int main() {
          int pipe_fd[2];         
          char buffer[50];

          if (pipe(pipe_fd) == -1) {
              perror("Pipe creation failed");
              return 1;
          }

          write(pipe_fd[1], "Hello, Pipe!", 13);
          read(pipe_fd[0], buffer, sizeof(buffer));

          printf("Received message: %s\n", buffer);

          return 0;
      }

b. 消息队列
- 消息队列用于在进程之间传递消息,通过msggetmsgsndmsgrcv等系统调用实现。

     // 文件1:msg_send.c
     #include <stdio.h>
     #include <sys/msg.h>         

     struct msg_buffer {
         long msg_type;
         char msg_text[50];
     };

     int main() {
         // 创建消息队列
         key_t key = ftok("msg_send.c", 65);
         int msgid = msgget(key, 0666 | IPC_CREAT);

         // 发送消息
         struct msg_buffer message;
         message.msg_type = 1;
         sprintf(message.msg_text, "Hello, Message Queue!");
         msgsnd(msgid, &message, sizeof(message), 0);

         return 0;
     }
     // 文件2:msg_receive.c   
     #include <stdio.h>
     #include <sys/msg.h>

     struct msg_buffer {
         long msg_type;
         char msg_text[50];
     };

     int main() {
         // 获取消息队列
         key_t key = ftok("msg_send.c", 65);
         int msgid = msgget(key, 0666 | IPC_CREAT);

         // 接收消息
         struct msg_buffer message;
         msgrcv(msgid, &message, sizeof(message), 1, 0);

         printf("Received message: %s\n", message.msg_text);

         // 删除消息队列
         msgctl(msgid, IPC_RMID, NULL);

         return 0;
     }

c. 信号(Signal)
- 信号用于在进程之间传递简单的通知,通过kill等系统调用发送信号。

     #include <stdio.h>
     #include <signal.h>      

     int main() {
         // 信号处理函数
         void sig_handler(int signo) {
             if (signo == SIGUSR1) {
                 printf("Received SIGUSR1\n");
             }
         }

         signal(SIGUSR1, sig_handler); // 注册信号处理函数

         // 发送信号
         kill(getpid(), SIGUSR1);

         return 0;
     }

d. 共享内存
- 共享内存允许多个进程共享一块内存区域,通过shmgetshmat等系统调用实现。

      // 文件1:shm_write.c
      #include <stdio.h>
      #include <sys/ipc.h>        
      #include <sys/shm.h>

      int main() {
          // 创建共享内存
          key_t key = ftok("shm_write.c", 65);
          int shmid = shmget(key, 1024, 0666 | IPC_CREAT);

          // 连接到共享内存
          char *str = (char*)shmat(shmid, (void*)0, 0);

          // 写入数据
          sprintf(str, "Hello, Shared Memory!");

          // 分离共享内存
          shmdt(str);

          return 0;
      }
     // 文件2:shm_read.c
     #include <stdio.h>
     #include <sys/ipc.h>     
     #include <sys/shm.h> 

     int main() {
         // 获取共享内存
         key_t key = ftok("shm_write.c", 65);
         int shmid = shmget(key, 1024, 0666 | IPC_CREAT);

         // 连接到共享内存
         char *str = (char*)shmat(shmid, (void*)0, 0);

         printf("Data read from shared memory: %s\n", str); 

         // 分离共享内存
         shmdt(str);

         // 删除共享内存
         shmctl(shmid, IPC_RMID, NULL);

         return 0;
     }

e. 信号量
- 信号量用于进程间的同步与互斥,通过sem_opensem_waitsem_post等系统调用实现。

      // 文件1:semaphore_create.c
      #include <stdio.h>
      #include <semaphore.h>
      #include <fcntl.h>           

      int main() {
          // 创建信号量
          sem_t *sem = sem_open("/my_semaphore", O_CREAT, 0644, 1);

          // 进行信号量操作
          sem_wait(sem);

          // 其他进程间的操作

          sem_post(sem);

          // 关闭并删除信号量
          sem_close(sem);
          sem_unlink("/my_semaphore");

          return 0;
      }
      // 文件2:semaphore_use.c
      #include <stdio.h>
      #include <semaphore.h>

      int main() {
          // 打开现有的信号量
          sem_t *sem = sem_open("/my_semaphore", O_CREAT);

          // 进行信号量操作
          sem_wait(sem);

          // 其他进程间的操作

          sem_post(sem);

          // 关闭信号量
          sem_close(sem);

          return 0;
      }

8. 进程监控和管理工具

a. ps命令
- 查看当前系统进程的详细信息。

      ps aux

b. top命令
- 实时查看系统进程的运行情况,包括CPU、内存的占用情况。

      top

c. htop工具
- htop是一个交互式的进程查看工具,提供了更友好的界面和操作。

      htop

d. pstree命令
- 显示进程树,展示进程之间的关系。

     pstree

9. Shell脚本与进程控制

a. 后台运行进程
- 使用&符号将进程放置到后台运行。

     ./my_process &

b. 前台运行进程
- 在终端直接运行进程,该进程将占用当前终端。

     ./my_process

c. 进程的暂停和继续
- 使用Ctrl + Z可以将前台运行的进程暂停,使用bgfg命令可以将进程放到后台或前台运行。

      Ctrl + Z
      bg
      fg

10. 实际应用和案例分析

a. 进程的实际应用场景
- 详细描述一个实际应用场景,例如Web服务器中的进程管理。

b. 分析一个实际进程的状态和资源使用情况
- 使用pstop等工具分析一个正在运行的进程,查看其状态和资源占用情况。

11. 安全性与权限

a. 进程的权限管理
- 说明进程的权限是如何管理和分配的。

b. susudo命令
- su用于切换用户,sudo用于以超级用户权限执行命令。

     su username
     sudo command
  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值