首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >简单叉()程序

简单叉()程序
EN

Stack Overflow用户
提问于 2020-04-06 14:56:27
回答 2查看 157关注 0票数 0

我正在尝试做一个程序,检查蒸汽服务器列表使用叉子。我看到,如果我经常放置100.000行服务器,程序就会进入一个有线循环,并一遍又一遍地检查相同的服务器。调试之后,我看到,即使是打印服务器ip的简单程序也会出现意外情况。

计划:

代码语言:javascript
运行
复制
#include <iostream>
#include <sys/wait.h>
#include <stdio.h>
#include <cstring>
#include <unistd.h>
#include <string>

#include <ctype.h>
#include <stdlib.h>
#include <fstream>

#include <sstream>
#include <algorithm>
#include <iterator>
#include <regex>
#include <vector>

int main(int argc, char **argv)
{
    puts("Beginning program");

    int max_forks = 500;
    int num_forks = 0;

    FILE *fpxxx = fopen("servers", "r");
    if(fpxxx == NULL) {
        perror("Unable to open file!");
        exit(0);
    }

    char chunk[128];

    while(fgets(chunk, sizeof(chunk), fpxxx) != NULL)
    {
        // puts(chunk); // same result if put the line here

        if(!(fork()))
        {
            // sleep(3);
            puts(chunk);

            exit(0);
        }
        else
        {
            num_forks++;

            if (num_forks >= max_forks)
            {
                wait(NULL);
                num_forks--;
            }
        }
    }

    fclose(fpxxx);
    sleep(10);
}

输出:

代码语言:javascript
运行
复制
Beginning forking
94.xxx.xxx.209

Beginning forking
184.xxx.xxx.117

Beginning forking
108.xxx.xxx.86

Beginning forking
178.xxx.xxx.140

Beginning forking
113.xxx.xxx.132

Beginning forking
45.xxx.xxx.16

... (many lines, thus servers.txt has 100.000+ ips)

# after a while i see
Beginning forking
178.xxx.xxx.140
# again and again and again


# sometimes i even see
Beginning forking
37.247.104.933.17.199.143

预期产出:

代码语言:javascript
运行
复制
94.xxx.xxx.209
184.xxx.xxx.117
108.xxx.xxx.86
178.xxx.xxx.140
113.xxx.xxx.132
45.xxx.xxx.16

我是不是忘了什么?堆好像坏了。为什么我看到Beginning forking就像程序从一开始就重新运行一样?我知道分叉正在进行另一个进程,但我认为fork()fork()的角度对程序进行了分叉。

谢谢。

编辑:解决方案是getline() is repeatedly reading the file, when fork() is used

EN

回答 2

Stack Overflow用户

发布于 2020-04-07 12:30:58

您在这里有几个问题:

  • ,您没有检查fork(2)的结果。这是目前为止最严重的问题,因为你正在做100,000个叉子。如您的手册页面所示,fork()在子进程中返回0,在父进程中返回子pid,如果执行正确,则返回。但是,在您的情况下,fork()将很快给您一个错误,因为您可能无法在系统中启动10万个同时进程。如果出现错误,fork()将返回-1,并且不检查它,因此,一旦它无法生成新进程,您将以if命令的else部分结束,将错误视为父进程中的一个成功的命令叉。这很可能导致一些不好的事情。正如在回答问题的另一个答案中告诉您的那样,如果尝试调用exit(3)而不是_exit(2),您将收到很多重复的输出(缓冲区内容),因为atexit()功能不足以同时刷新父级和子级的stdio缓冲区。在终端输出中,这种情况不会发生(您不会看到这一点),因为stdiostdout上对终端使用行缓冲,因此它会在出现fork()之前刷新缓冲区。但是,只有当输出设备是终端时,而不是如果它是一个文件(其中缓冲区只有在缓冲区已满时才被刷新,或者在退出时,所有非刷新的stdio缓冲区都被刷新)。当我假设您正在某个文件中搜索时,我假设您已经将输出重定向到一个文件,因此需要进行大量重复输出。
  • 也不是在结束时进行sleep(10)调用,而是等待子进程完成,使用循环,对子进程使用wait(2)来终止,直到从wait获得错误为止。这将意味着你没有更多的孩子活着。

  • ,这是最重要的事情。所有系统调用都记录在在线手册页面中。请使用它们,因为我已经解释过的所有内容都在这里。
  • 是一个小问题。您正在使用旧的C库调用来执行C++中的I/O (C++是一个例子)。尽量避开他们。C++被设计成能够使用所有C语言调用,因此许多遗留软件是可重用的,并且可以在C++中工作。对于许多遗留库来说都是这样,但是很久以前,stdio被一个设计得更好的库(iostream)所取代(因为新语言中新的面向对象功能,而不是说Stroustrup比Kernighan或Ritchie好,我事先表示歉意),所以,在C++中使用C/O是强烈反对的。

您将从所有这些注释中看到,您的解决方案不是以调用getline()的方式解决的,因为您的代码中存在严重的问题。

票数 1
EN

Stack Overflow用户

发布于 2020-04-06 20:54:35

代码语言:javascript
运行
复制
    if(!(fork()))
    {
        // sleep(3);
        puts(chunk);

        exit(0);
    }

这应该是_exit(0);。否则,您将多次执行退出处理程序,这会对共享文件描述符等事情产生不可预测的影响。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61062646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档