阻塞等待
一般在内核中阻塞(伴随着被切换),等待被唤醒(放在等待队列【一种数据结构】中)
在Linux中,阻塞等待是指一个进程或线程被暂停执行,直到某个条件满足或事件发生。下面介绍两种常见的阻塞等待方式:
-
阻塞等待系统调用:在Linux中,许多系统调用函数可以使进程或线程进入阻塞等待状态,直到某个条件满足。例如,常见的阻塞等待系统调用包括:
read()
:从文件描述符中读取数据,如果没有数据可读,则进程会阻塞等待,直到有数据可读或出现错误。write()
:向文件描述符中写入数据,如果写入的缓冲区已满,则进程会阻塞等待,直到有空间可写或出现错误。sleep()
:使进程休眠指定的时间,进程会阻塞等待,直到休眠时间结束。wait()
:等待子进程结束,进程会阻塞等待,直到子进程结束或出现错误。
当条件满足时,阻塞等待的系统调用会返回,并使进程或线程继续执行。
-
阻塞等待同步原语:除了系统调用外,Linux还提供了一些同步原语,用于实现线程之间的阻塞等待。这些同步原语包括:
- 互斥锁(Mutex):线程可以使用互斥锁来保护共享资源,当一个线程持有互斥锁时,其他线程尝试获取锁会被阻塞等待,直到锁被释放。
- 条件变量(Condition Variable):线程可以使用条件变量来等待某个条件满足,当条件不满足时,线程会阻塞等待在条件变量上,直到其他线程发出条件满足的信号。
- 信号量(Semaphore):线程可以使用信号量来控制对共享资源的访问,当信号量的值为0时,线程会阻塞等待,直到信号量的值大于0。
这些同步原语可以帮助线程进行有效的互斥和同步,并实现线程之间的阻塞等待。
非阻塞等待
非阻塞等待是指进程或线程在等待某个条件满足时,不会被暂停执行,而是继续执行其他任务。在Linux中,非阻塞等待通常使用以下两种方式实现:
-
轮询:进程或线程可以通过轮询的方式来检查条件是否满足。它会反复地检查条件,如果条件满足,则继续执行相应的操作;如果条件不满足,则继续轮询或执行其他任务。轮询可以使用循环结构实现,例如使用
while
循环。以下是一个简单的示例,展示了如何使用轮询实现非阻塞等待:
while (!condition) {// 执行其他任务 } // 条件满足,执行相应的操作
轮询的优点是简单直接,但它可能会消耗大量的CPU资源,并且可能导致延迟。
-
异步事件处理:进程或线程可以将等待任务交给操作系统或其他模块处理,并在条件满足时通过回调函数或事件通知方式得到通知。这样,进程或线程可以继续执行其他任务,而不需要主动轮询。
异步事件处理通常涉及使用特定的API或框架,例如Linux中的
epoll
、select
、poll
等系统调用,或者使用异步编程框架,例如libevent、Boost.Asio等。以下是一个简单的示例,展示了如何使用异步事件处理实现非阻塞等待:
// 创建事件循环 event_loop = create_event_loop();// 注册事件处理函数 register_event_handler(event_loop, event_type, event_handler);// 启动事件循环 run_event_loop(event_loop);
当事件发生时,事件处理函数
event_handler
将被调用,进程或线程可以在事件处理函数中执行相应的操作。异步事件处理的优点是可以提高系统的性能和响应性,但它通常需要更复杂的编程模型和代码结构。
非阻塞等待在处理异步任务和事件驱动编程中非常常见,它可以提高系统的并发性和吞吐量。具体使用哪种非阻塞等待方式取决于您的需求和场景。如果您有特定的问题或需求,请提供更多详细信息,我将尽力提供帮助。
进程替换
替换原理
内核结构没有变,并没有创建新的进程
如何理解将程序放入内存当中:加载!exec*系列函数
可变参数列表最后一个参数必须是NIULL,标识参数传递完毕!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>int main()
{extern char **environ;pid_t id = fork();if(id == 0){//childprintf("我是子进程: %d\n", getpid());//execl: 如果替换成功,不会有返回值,如果替换失败,一定有返回值 ==》如果失败了,必定返回 ==》 只要有返回值,就失败了//不用对该函数进行返回值判断,只要继续向后运行一定是失败的!//execl("/bin/ls", "ls", "-a", "-ln", NULL); //lsssss: 不存在//char *const myargv[] = {// "ls",// "-a",// "-l",// "-n",// NULL//};//execv("/bin/ls", myargv); //lsssss: 不存在//execlp("ls", "ls", "-a", "-l", "-n", NULL);//execvp("ls", myargv);//char *const myenv[] = {// "MYENV=YouCanSeeMe",// NULL//};//putenv("MYENV=YouCanSeeMe");//execle("./exec/otherproc", "otherproc", NULL, environ);//execl("./exec/shell.sh", "shell.sh", NULL);execl("./exec/test.py", "test.py", NULL);exit(1);}sleep(1);//fatherint status = 0;printf("我是父进程: %d\n", getpid());waitpid(id, &status, 0);printf("child exit code: %d\n", WEXITSTATUS(status));return 0;
}