1

こんにちは、並列ダウンロード プログラムについて少し助けが必要です。

現在、複数のファイルを同時にダウンロードするのではなく、同じファイルを並行してダウンロードしています。

forkとに問題がありfgetsます。修正方法がわかりません。ありがとうございました。

#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
FILE *file; /*declare the file pointer*/
#define LINE_MAX 1000
char line [LINE_MAX];
//Parent process
int main()
{
pid_t  pid;
file= fopen ("urls.txt", "rt"); /*open file and read it*/

if(!file)
{
    perror("fopen");
    exit(-1);
}

int numberOfChildren = 0;

while (!feof (file)) {

memset (line,'\0',1000);

char *urlPtr; 


while (!feof (file))
{
urlPtr= fgets (line,LINE_MAX, file);

if(urlPtr)
{

int lineLen = strlen(urlPtr);
urlPtr[lineLen-1] = '\0';
pid = fork();
++numberOfChildren;

    if (pid == 0) {  /* child process */
        execlp("/usr/bin/wget", "wget", urlPtr, NULL);
        }

    else if (pid < 0) { /* error occurred */
        fprintf(stderr, "Fork Failed");
        exit(-1);
        }
}
}
    while (numberOfChildren>0) { /* parent process */
    /* parent will wait for the child to complete */
        wait (NULL);
        --numberOfChildren;
        printf ("Child Complete");
        }



}   
fclose (file); /*close file command*/


return 0;
}
4

2 に答える 2

3

URL 読み取りループの外に fork() チェックがあります。最初に多数の URL を読み取り、多数の子を生成してから、pid チェックを行います。試す

while (!feof (file))
{
    urlPtr= fgets (line,LINE_MAX, file);
    pid = fork();
    if (pid == 0) {  /* child process */
         execlp("/usr/bin/wget", "wget", urlPtr, NULL);
    }
    else if (pid < 0) { /* error occurred */
        fprintf(stderr, "Fork Failed");
        exit(-1);
    }
    ++numberOfChildren;
}
于 2012-09-23T23:07:06.740 に答える
1

診断印刷を配置し、の後に終了する必要がありますexeclp()(ただし、の後に子コードを挿入しますif)。実行する前に、おそらく入力ファイルも閉じる必要がありますwget。プログラムはそれを開く必要はありません。今回は大きな害はありませんが、整頓するのは良いことです。1人の子供が失敗したという理由だけで、親が終了するべきではないでしょうfork()。一般的に、あなたには他の子供がいて、それを待つ必要があります。ただし、その時点でファイルの処理を停止する場合があります。そして、あなたは間違いなく忘れるべきfeof()です; を使用while (fgets(line, sizeof(line), file) != 0)しますが、それはあなたが必要としないことを意味しますurlPtr。はmemset()不要です。fgets()文字列を正しく初期化します。

問題のコードの適応

#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

FILE *file; /*declare the file pointer*/
#define LINE_MAX 1000
char line [LINE_MAX];

//Parent process
int main(void)
{
    pid_t  pid;
    file = fopen("urls.txt", "rt"); /*open file and read it*/

    if (!file)
    {
        perror("fopen");
        exit(-1);
    }
    int numberOfChildren = 0;
    memset(line,'\0',1000);
    char *urlPtr; 

    while (!feof(file))
    {
        urlPtr= fgets(line, sizeof(line), file);
        if (urlPtr)
        {
            int lineLen = strlen(urlPtr);
            urlPtr[lineLen-1] = '\0';
            pid = fork();

            ++numberOfChildren;

            if (pid == 0)
            {   /* child process */
                execlp("/usr/bin/wget", "wget", urlPtr, NULL);
                fprintf(stderr, "%d: wget failed\n", (int)getpid());
                exit(1);
            }
            else if (pid < 0)
            {   /* error occurred */
                fprintf(stderr, "Fork Failed\n");
                exit(-1);
            }
            else
                printf("%d: %s\n", (int)pid, urlPtr);
        }
    }

    /* JL: Moved block of code */
    while (numberOfChildren>0)
    {   /* parent process */
        /* parent will wait for the child to complete */
        int status;
        int corpse = wait(&status);
        --numberOfChildren;
        printf("Child %d Complete (0x%04X)\n", corpse, status);
    }

    fclose(file); /*close file command*/

    return 0;
}

while (!feof(file))ループは削除されていますが、不要なコードがさらに存在する可能性があることに注意してください。与えられたデータファイル

ftp://ftp.iana.org/tz/releases/tzcode2012f.tar.gz
ftp://ftp.iana.org/tz/releases/tzdata2012f.tar.gz

上記のコードは、2つのファイルを並行してフェッチするように機能します。

代替コード

一度使用するコードが比較的短い場合でも、関数を使用するのが好きです。したがって、be_childish()以下に追加された関数。エラー報告は書き出すのが少し面倒ですが、それを行わない理由にはなりません。

私自身の精巧なライブラリに基づいてエラー報告を行う最小限の関数を簡単に紹介しましたが、このコードでは2回しか使用されません(ファイルオープンエラーとexeclp()リターン後、常に無条件に失敗を示します)が、決定しましたそれを省くために。、、などの関数が err_setarg0()あり、err_error()それらを使用すると、各エラーレポートが1行に減ります(さらに、PIDを自動的に含めるように指示できるいくつかのより複雑な関数など)。私にとっては、このようなライブラリを使用する価値があります。これにより、エラーチェックがはるかに簡単になり、苦痛が少なくなり、無駄になりにくくなります。err_remark()err_usage()

#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

static void be_childish(const char *urlPtr)
{
    const char *wget = "/usr/bin/wget";
    char *nl = strchr(urlPtr, '\n');
    if (nl != 0)
        *nl = '\0';
    printf("%d: %s\n", (int)getpid(), urlPtr);
    execlp(wget, "wget", urlPtr, NULL);
    fprintf(stderr, "%d: Failed to execute %s\n", (int)getpid(), wget);
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    FILE *file;
    char line [1024];
    pid_t  pid;
    const char *name = "urls.txt";
    int rc = EXIT_SUCCESS;

    if (argc == 2)
        name = argv[1];
    else if (argc > 2)
    {
        fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    file = fopen(name, "rt");   /* Undefined behaviour per POSIX */
    int numberOfChildren = 0;

    if (file == 0)
    {
        fprintf(stderr, "Failed to open file %s\n", name);
        exit(EXIT_FAILURE);
    }

    while (fgets(line, sizeof(line), file) != 0)
    {
        if ((pid = fork()) == 0)
        {
            fclose(file);
            be_childish(line);
        }
        else if (pid < 0)
        {
            fprintf(stderr, "Fork Failed");
            rc = EXIT_FAILURE;
            break;
        }
        ++numberOfChildren;
    }
    fclose(file);

    /* Parent waits for the children to complete */
    while (numberOfChildren > 0)
    {
        int status;
        const char *result = "OK";
        pid = wait(&status);
        --numberOfChildren;
        if (status != 0)
        {
            result = "Failed";
            rc = EXIT_FAILURE;
        }
        printf("Child %d %s\n", pid, result);
    }

    return rc;
}

コードはコマンドラインでファイル名を取り、デフォルトは「urls.txt」であることに注意してください。"rt"オープンモードはPOSIXまたは標準のCモードではありません。おそらく機能"r"しますが、すべてのシステムでテキストファイルを開くには十分です("rb"バイナリファイルを開くにはすべてのシステムで機能し、POSIXおよび標準Cに準拠しています)。リストされた各ファイルを処理している子プロセスを報告します。各子のステータス(成功または失敗)を報告します。それ自体の終了ステータスは、すべての子が成功した場合にのみ成功します。

おそらく、コマンドラインから冗長性を制御できます。また、ユーザーが実際に気にしないプロセスではなく、正常にダウンロードされたファイルについてレポートできるように、どの子が各ファイルを処理していたかを記録しておくこともできます。読むときに各URLのコピーを作成する必要があるため、処理が複雑になります。

に渡す前に、文字列(URL)の末尾から改行を削除する必要があることに注意してくださいwget


このコードは(改行修正を追加した後)テストされ、2つのファイルが生成されました。画面表示は少し混乱しています。これは、の各コピーがwgetそれが唯一のユーザーであると考えているためです。

80334: ftp://ftp.iana.org/tz/releases/tzcode2012f.tar.gz
80335: ftp://ftp.iana.org/tz/releases/tzdata2012f.tar.gz
--2012-09-23 19:19:44--  ftp://ftp.iana.org/tz/releases/tzcode2012f.tar.gz
           => “tzcode2012f.tar.gz”
Resolving ftp.iana.org... --2012-09-23 19:19:44--  ftp://ftp.iana.org/tz/releases/tzdata2012f.tar.gz
           => “tzdata2012f.tar.gz”
Resolving ftp.iana.org... 192.0.32.8192.0.32.8, , 2620:0:2d0:200::82620:0:2d0:200::8

Connecting to ftp.iana.org|192.0.32.8|:21... Connecting to ftp.iana.org|192.0.32.8|:21... connected.
Logging in as anonymous ... connected.
Logging in as anonymous ... Logged in!
==> SYST ... Logged in!
==> SYST ... done.    ==> PWD ... done.    ==> PWD ... done.
==> TYPE I ... done.
==> TYPE I ... done.  ==> CWD (1) /tz/releases ... done.  ==> CWD (1) /tz/releases ... done.
==> SIZE tzdata2012f.tar.gz ... done.
==> SIZE tzcode2012f.tar.gz ... 206404
==> PASV ... 135543
==> PASV ... done.    ==> RETR tzdata2012f.tar.gz ... done.    ==> RETR tzcode2012f.tar.gz ... done.
Length: 206404 (202K) (unauthoritative)

 0% [                                                                               ] 0           --.-K/s              done.
Length: 135543 (132K) (unauthoritative)

100%[==============================================================================>] 135,543     72.7K/s   in 1.8s    

100%[==============================================================================>] 206,404     81.4K/s   in 2.5s    

2012-09-23 19:19:48 (72.7 KB/s) - “tzcode2012f.tar.gz” saved [135543]

Child 80334 OK
2012-09-23 19:19:48 (81.4 KB/s) - “tzdata2012f.tar.gz” saved [206404]

Child 80335 OK
于 2012-09-24T01:26:41.820 に答える