Shaw0xyz 发表于 2024-5-28 17:45:34

Linux进程等待

本帖最后由 Shaw0xyz 于 2024-5-28 17:47 编辑

在 Linux 操作系统中,进程管理是一个重要的组成部分。进程等待是指一个进程在执行过程中需要等待某个事件的发生,比如等待某个文件的读写完成,等待某个信号的到来等。本文将深入探讨 Linux 中进程等待的概念、常见方法以及应用场景。


1. 进程等待的概念

进程等待是指一个进程在某种条件未满足时,进入等待状态,暂停执行,直到条件满足时再恢复执行。这种机制可以提高系统资源的利用率,避免进程无效地占用 CPU 时间。

2. 常见的进程等待方法

2.1 阻塞等待

阻塞等待是指进程主动放弃 CPU 使用权,进入阻塞状态,等待某个事件的发生。当事件发生时,内核将进程从阻塞状态唤醒,恢复执行。

2.1.1 使用 `sleep` 函数

`sleep` 函数使进程在指定的时间段内进入睡眠状态。


#include <unistd.h>

int main() {
    sleep(5); // 进程将等待5秒
    return 0;
}


2.1.2 使用 `read` 函数

`read` 函数在读取数据时,如果没有数据可读,进程将进入阻塞状态,直到有数据可读或发生错误。


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

int main() {
    int fd = open("test.txt", O_RDONLY);
    char buffer;
    read(fd, buffer, sizeof(buffer)); // 进程在读取数据时阻塞
    close(fd);
    return 0;
}


2.2 非阻塞等待

非阻塞等待是指进程在等待某个事件时,不放弃 CPU 使用权,而是不断地检查条件是否满足。如果条件不满足,进程继续执行其他任务。

2.2.1 使用 `O_NONBLOCK` 标志

在打开文件时使用 `O_NONBLOCK` 标志,可以使读写操作变为非阻塞模式。


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

int main() {
    int fd = open("test.txt", O_RDONLY | O_NONBLOCK);
    char buffer;
    int n = read(fd, buffer, sizeof(buffer));
    if (n == -1 && errno == EAGAIN) {
      printf("No data available\n");
    }
    close(fd);
    return 0;
}


2.3 信号等待

信号等待是指进程在等待某个信号时进入等待状态,当信号到来时,内核唤醒进程,进程处理信号。

2.3.1 使用 `pause` 函数

`pause` 函数使进程进入睡眠状态,直到收到信号。


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

void handler(int signum) {
    printf("Signal received\n");
}

int main() {
    signal(SIGINT, handler);
    pause(); // 进程等待信号
    return 0;
}


2.3.2 使用 `sigwait` 函数

`sigwait` 函数使进程在指定的信号集中等待信号。


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

int main() {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);

    int signum;
    sigwait(&set, &signum); // 进程等待信号
    printf("Signal received: %d\n", signum);
    return 0;
}


3. 应用场景

3.1 多进程编程

在多进程编程中,父进程可以使用 `wait` 或 `waitpid` 函数等待子进程的结束,以便获取子进程的退出状态。


#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {
      // 子进程
      sleep(2);
      return 42;
    } else {
      // 父进程
      int status;
      waitpid(pid, &status, 0); // 父进程等待子进程结束
      if (WIFEXITED(status)) {
            printf("Child exited with status %d\n", WEXITSTATUS(status));
      }
    }
    return 0;
}


3.2 网络编程

在网络编程中,服务器进程可以使用 `select` 或 `poll` 函数等待多个文件描述符的事件。


#include <sys/select.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);

    int ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, NULL); // 等待输入
    if (ret > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
      char buffer;
      read(STDIN_FILENO, buffer, sizeof(buffer));
      printf("Input: %s\n", buffer);
    }
    return 0;
}


3.3 文件 I/O

在文件 I/O 操作中,进程可以使用 `epoll` 等机制等待文件描述符的事件,提高效率。


#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
    int epfd = epoll_create1(0);
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = STDIN_FILENO;
    epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);

    struct epoll_event events;
    int nfds = epoll_wait(epfd, events, 10, -1); // 等待事件
    if (nfds > 0) {
      char buffer;
      read(events.data.fd, buffer, sizeof(buffer));
      printf("Input: %s\n", buffer);
    }
    close(epfd);
    return 0;
}


4. 总结

本文详细介绍了 Linux 进程等待的概念、常见方法以及应用场景。通过掌握这些内容,可以在实际开发中合理地使用进程等待机制,提高程序的效率和响应速度。希望本文对您有所帮助。

页: [1]
查看完整版本: Linux进程等待