b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

总结:Linux没有写回磁盘,脏数据,进程结束

电脑杂谈  发布时间:2020-09-11 03:03:36  来源:网络整理

exit函数不兼容_exit函数实现_exit函数会清空内存吗

实际上,在父进程中调用fork()之后有两个结果:一个是拆分子进程失败,另一个是拆分子进程成功。如果fork()失败,则返回-1;否则,将有两个进程,一个父进程和一个子进程。 Fork()在子进程中返回0,而fork()在父进程中返回子进程的ID。系统调用fork()的工作流程图如下:

exit函数会清空内存吗

换句话说,您需要在fork()函数之前确认内核中有足够的资源来完成。如果资源满足要求,则内核平板分配器将在相应的缓冲区中构造子进程的进程控制块,并将父进程控制块中的所有成员复制到子进程控制块,然后再将其复制到子进程控制块。必要的私有数据将更改为子进程的数据。在fork()返回用户空间之前,将返回值0推送到子进程的内核堆栈中,并将子进程的pid推送到父进程的内核堆栈中。最后,执行进程调度来确定是运行子进程还是运行父进程。

很显然,为了使子例程和父程序能够执行不同的代码,应根据fork()之后的fork()的返回值,使用分支结构来组成程序代码。例如:

#include 
#include 
int main(void)
{
    pid_t pid;
    pid = fork();
    if(pid < 0){
        ...                //打印fork()失败信息
    }else if(pid == 0){
        ...                //子进程代码
    }else{
        ...                //父进程代码
    }
    return 0;
}

在代码中获取当前进程的pid的函数是:getpid();

在代码中获取当前进程的父进程的pid的函数是:getppid()。

这里需要注意一点:父进程和子进程的调度顺序由调度程序确定,与进程的创建顺序无关。

关于子进程的时间片

与UCOSIII不同,Linux在大多数情况下都是根据时间片来调度进程。当某个进程拥有的时间片用完时,内核将立即剥夺其运行和停止执行的权利。因此,当创建子进程时,子进程的初始时间段应为多大?

Linux规定,如果父进程像以前一样简单地创建一个子进程,那么系统会将父进程的剩余时间片分为两部分,一个用于父进程,另一个作为子进程的时间。工艺表。因为以前以这种简单的方式,父进程和子进程使用相同的代码并且没有成为两个真正独立的进程,所以它们没有资格享受两个时间片。

与进程相关的系统调用函数execv()

为了在程序运行时加载并运行可执行文件,Linux提供了系统调用execv()。原型是:

int execv(const char* path, char* const argv[]);

其中,参数路径是可执行文件路径,而argv []是命令行参数。

exit函数不兼容_exit函数会清空内存吗_exit函数实现

如果某个进程调用execv(),则该函数会将函数参数路径指定的可执行文件加载到该进程的用户存储空间中,覆盖原始文件,然后运行新加载的可执行文件。

在实际应用中,通常是调用execv()的子进程。人们创建子进程的原因是要执行与父进程代码不同的程序,而系统调用execv()是子进程执行新程序的方法之一。子进程调用execv()之后,系统将立即为子进程分配一个专用程序内存空间,以加载可执行文件,并且从此以后,该子进程已成为实际进程。

如进程是父进程的“儿子”,则在子进程调用execv()之前,其单独的用户堆栈和数据区域仅等效于其私有“房间”;但是由于它也没有自己的“住房”,因此尽管它有自己的“户口”(过程控制块),但它只能住在“父亲”的房子里,而不能“自给”。

调用execv()之后,父进程和子进程的存储结构如下:

exit函数会清空内存吗

与上面的fork()的内存映射相比,调用fork()之后,父子共享相同的程序代码;并在调用execv()之后,该子例程具有其自己的程序代码区域。

示例:

#include 
#include 
int main(void)
{
    pid_t pid;
    if(!(pid=fork())){
        execv("./hello.o",NULL);
    }else {
        printf("my pif is %d\n", getpid());
    }
    return 0;
}

可执行文件./hello.o可以通过编写.c程序然后进行编译来获取。

函数execv()实际上是Linux的exec函数家族的成员之一。函数族有5个函数和1个系统调用,分别是:

int execl(const char* path, const char* arg, ...);
int execlp(const char* file, const char* arg, ...);
int execle(const char* path, const char* arg, ..., char* const envp[]);
int execv(const char* path, const char* argv[]);
int execvp(const char* file, const char* argv[]);
int execve(const char* path, const char* argv[], char* const envp[]);

其中,只有execv()是真正意义上的系统调用,其他是在此基础上打之父”,并且init进程负责在“ orphan进程”结束后释放资源。

这是僵尸进程和孤立进程之间的区别:

Linix提供了一种机制,以确保只要父进程想知道子进程末尾的状态信息,就可以获取它。这种机制是:当每个进程退出时,内核会释放该进程的所有资源,包括打开的文件,占用的内存等。但是,仍然为它保留某些信息(包括进程ID,进程的终止状态,进程占用的CPU时间等)。在等待/ waitpid获取父进程之前,不会释放它。但这导致一个问题。如果进程不调用wait / waitpid,则保留的信息将不会被释放,并且其进程ID将始终被占用,但是系统可以使用的进程ID受到限制。僵尸进程将导致系统无法生成新进程,因为没有可用的进程号。这是僵尸进程的危害,应该避免。

参考文章:孤立过程和僵尸过程[摘要]。

系统调用exit()

系统调用exit()用于终止进程。通常,将在与过程控制相关的某些系统调用中调用此系统调用。

如果某个进程调用exit(),则该进程将立即退出并负责释放中止进程的各种内核数据结构,但进程控制块除外。这种仅具有“ ID卡”的进程称为“僵尸进程”,其进程控制块域状态值为TASK_ZOMBLE。

通过调用exec函数族函数执行新的可执行文件的子进程。当进程结束时,它将执行系统调用exit()以使其自身成为“僵尸进程”,该进程也是父进程。该进程负责销毁子进程的进程控制块。

此外,exit()一直执行到最后,流程调度功能schedule()将被调用以进行流程调度。

这是exit()和_exit()函数之间的区别:

exit()在stdlib.h文件中定义,而_exit()在unistd.h文件中定义。同时,两者的步骤也不同:

exit函数实现_exit函数不兼容_exit函数会清空内存吗

exit函数会清空内存吗

具体体现在什么地方?

在Linux标准库中,有一组高级I / O功能。例如,此列中包含著名的printf,fopen,fread和fwrite,它们也称为缓冲I / O。它的特点是每个打开的文件都有一个缓冲区,每次读取文件都会读取更多记录,以便下次读取文件时,可以直接从内存中的缓冲区读取它。每次写入文件时,缓冲区也会先写入。当缓冲区已满,或者我们fflush()手动刷新缓冲区,或者遇到诸如\ n,EOF之类的结束字符时,将从中删除相应的数据。缓冲区被写入文件。这具有大大提高文件读写速度的优点,因为我们都知道磁盘上的读写速度非常慢,但这也给我们的编程带来了一些麻烦。例如,我们认为某些数据已写入文件,但实际上它们很可能存在于缓冲区中。

换句话说,_exit()的功能是直接停止该进程,清除其使用的内存空间,并清除其在内核中的各种数据结构。 exit()函数基于这些功能。对于某些小动作,在退出之前添加了几个过程。 exit()函数和_exit()函数之间的最大区别是exit()函数在调用exit系统调用之前先检查文件的打开状态,并将文件缓冲区的内容写回到文件中。也就是说,图中的“清理I / O缓冲区”。

参考文章:退出函数和_exit函数之间的区别。

系统调用vfork()

vfork()是Linux提供的另一个系统调用,用于生成子进程。

与fork()不同,vfork()不会将所有父进程都复制到子进程,而仅使用分配指针的方法来共享子进程和父进程的资源。由于函数vfork()生成的子进程与父进程共享相同的内存空间,因此本质上vfork()创建线程,但是习惯上将其称为子进程。

使用vfork()创建一个子进程并调用execve()之后,该子进程的内存映像如下:

exit函数会清空内存吗

这是fork()和vfork()之间的区别:

注意:因为vfork()保证子进程先运行,所以可以安排父进程在调用execve()或exit()之后运行。如进程在调用这两个函数之前依赖于父进程的进一步操作,则会导致死锁。

内核中的进程和线程

操作系统是一个在其他程序之前运行的程序,因此,如果除操作系统之外,系统中没有其他进程,会发生什么情况?同时,系统中的所有用户进程都必须由父进程创建,那么“祖先进程”是什么?

前者的问题由Linux进程0解决,后者的问题由Linux进程1解决。实际上,前者是内核进程,而后者首先是内核进程,然后成为用户进程。

exit函数不兼容_exit函数实现_exit函数会清空内存吗

内核线程及其创建

Linux实现线程的机制非常独特。它没有额外定义线程数据结构和调度算法,但是在创建线程时不会为其分配单独的内存空间。如果线程在用户空间中运行,则它是用户线程;如果它在内核空间中运行,则它是一个内核线程。而且,无论是线程还是进程,Linux都使用相同的调度程序来调度它们。

但是Linux提供了一个单独的函数kernel_thread()来创建内核线程。此函数的原型如下:

int kernel_thread(int (* fn)(void *), void* arg, unsigned long flags);

其中,fn指向线程代码; arg是线程代码所需的输入参数。

内核线程是定期执行的,通常用于完成一些需要在内核后台执行的任务,例如刷新磁盘缓存,维护网络连接和交换页面,因此它们也称为内核任务

进程0

启动计算机后,首先启动并加载Linux。加载Linux内核后,初始化函数start_kernel()将立即创建一个内核线程。由于Linux并没有严格区分线程和进程,因此由初始化函数创建的线程称为进程0。

内核函数cpu_idel()是进程0的执行代码。此函数中只有一条hlt(暂停)指令;只有1个hlt(暂停)指令。换句话说,此过程不做任何工作,因此也称为空闲过程。此空闲进程的PCB称为init_task()。当系统没有其他可运行的进程时,调度程序将选择要运行的进程0。

过程1

进程1也称为init进程,它是初始化内核时创建的第二个内核线程,其运行代码是内核函数init()。

此函数首先创建4个与内存管理相关的内核线程,例如kswapd()。接下来,在内核的init()中调用execve()系统调用,以加载另一个需要在用户空间中运行的init函数代码,因此进程1成为普通进程。它是用户空间中的第一个进程,因此它成为其他用户进程的根进程。

只要是系统,init进程就永远不会终止。它负责创建和监视操作系统外部所有进程的活动。

守护进程

守护程序是不受终端控制且在后台运行的进程。 Linux使用大量守护程序在后台执行一些常规工作,例如常规注入和页面交换。

通常可以通过以下方式启动守护程序:


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-318374-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...