2009-03-16 10 views
3

私はいくつかの並列処理が有効なアプリケーションを持っています。議論の目的のために、10個のテキストファイルを含むディレクトリがあり、プログラムを開始したい、10個のプロセスをフォークし、それぞれがファイルの1つをとり、ファイルの内容を大文字にしたいとしましょう。私は親プログラムが子どもたちがの機能を待つか、の機能を使うか、を選択しての機能を使って子どもたちが完了するのを待つことができることを認めます。unix-fork-monitor-child-progress

親プロセスがフォークされた各プロセスの進行状況を監視し、プロセスが実行されるときにプログレスバーのようなものを表示させることをお勧めします。

私の質問。

フォークされたプロセスがこの情報を親に返信するうえで妥当な選択肢は何でしょうか?どんなIPC技術が使用するのが妥当でしょうか?

答えて

2

進捗状況の監視のみを行うこの種の状況では、最も簡単な方法は共有メモリを使用することです。すべてのプロセスは、共有メモリブロック上の進捗値(例えば、整数)を更新し、マスタプロセスはブロックを定期的に読み込む。基本的に、このスキームではロックは必要ありません。また、マスターは必要なときに情報を読み取ることができるため、進行状況データを処理するためのイベント処理は不要であるため、「ポーリング」スタイルのアプリケーションです。

+0

進捗の値がマルチバイトの場合、ロックが必要な場合があります(キャッシュからアライメントまでのあらゆる種類のものに依存します)。これは「オドメーター問題」と呼ばれていました。基本的に(そしてビッグエンディアンの10進数で)1999年から2000年にかけて、読者は1900年、2099年などを見るかもしれません – MarkusQ

0

今日、誰かがいつもパイプを使用していると言いました。これによって、子プロセスは親プロセスにすべてがうまくいっているという通知を送ることができます。これはまともな解決策であり、エラーを出力したいが、stdout/stderrなどにアクセスすることができない場所で特に便利です。

1

いくつかのオプションがあります

  • 信号
  • のFIFO /名前付きパイプ子供の
  • STDOUTまたは他渡さハンドル: - あなたは「大文字化ファイル」アナロジー)にoppedとして多くは、あなたが実際に何をしているかに依存します
  • メッセージキュー(該当する場合)
0

Boost.MPIは、このシナリオでは便利です。あなたはそれが行き過ぎ考えるかもしれませんが、それは間違いなく調査する価値がある:
www.boost.org/doc/html/mpi.html

1

あなたが望むすべてが進行アップデートであれば、はるかに最も簡単な方法は、匿名を使用することが考えられますパイプ。 pipe(2)呼び出しでは、パイプの各端に1つずつ、2つのファイル記述子が与えられます。あなたがフォークする直前にそれを呼び出し、親に最初のfdを聞かせ、子が2番目のfdに書き込むようにします。 (これは、ファイルディスクリプタとそれらを含む2要素配列の両方がプロセス間で共有されるため、共有メモリ自体ではなく、コピー時にコピーされるため、値を共有するためです)。

2

あなたが必要とする唯一の進展は、「完了したどのように多くの仕事?」であれば、簡単な

while (jobs_running) { 
    pid = wait(&status); 
    for (i = 0; i < num_jobs; i++) 
     if (pid == jobs[i]) { 
      jobs_running--; 
      break; 
     } 
    printf("%i/%i\n", num_jobs - jobs_running, num_jobs); 
} 

を行います。うまくいっている間に進行状況を報告するために、ここではいくつかの他の提案のダム実装を示します。

パイプ:

#include <poll.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <unistd.h> 

int child(int fd) { 
    int i; 
    struct timespec ts; 
    for (i = 0; i < 100; i++) { 
     write(fd, &i, sizeof(i)); 
     ts.tv_sec = 0; 
     ts.tv_nsec = rand() % 512 * 1000000; 
     nanosleep(&ts, NULL); 
    } 
    write(fd, &i, sizeof(i)); 
    exit(0); 
} 

int main() { 
    int fds[10][2]; 
    int i, j, total, status[10] = {0}; 
    for (i = 0; i < 10; i++) { 
     pipe(fds[i]); 
     if (!fork()) 
      child(fds[i][1]); 
    } 
    for (total = 0; total < 1000; sleep(1)) { 
     for (i = 0; i < 10; i++) { 
      struct pollfd pfds = {fds[i][0], POLLIN}; 
      for (poll(&pfds, 1, 0); pfds.revents & POLLIN; poll(&pfds, 1, 0)) { 
       read(fds[i][0], &status[i], sizeof(status[i])); 
       for (total = j = 0; j < 10; j++) 
        total += status[j]; 
      } 
     } 
     printf("%i/1000\n", total); 
    } 
    return 0; 
} 

共有メモリ:などの取り扱い

#include <semaphore.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 
#include <time.h> 
#include <unistd.h> 

int child(int *o, sem_t *sem) { 
    int i; 
    struct timespec ts; 
    for (i = 0; i < 100; i++) { 
     sem_wait(sem); 
     *o = i; 
     sem_post(sem); 
     ts.tv_sec = 0; 
     ts.tv_nsec = rand() % 512 * 1000000; 
     nanosleep(&ts, NULL); 
    } 
    sem_wait(sem); 
    *o = i; 
    sem_post(sem); 
    exit(0); 
} 

int main() { 
    int i, j, size, total; 
    void *page; 
    int *status; 
    sem_t *sems; 
    size = sysconf(_SC_PAGESIZE); 
    size = (10 * sizeof(*status) + 10 * sizeof(*sems) + size - 1) & size; 
    page = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 
    status = page; 
    sems = (void *)&status[10]; 
    for (i = 0; i < 10; i++) { 
     status[i] = 0; 
     sem_init(&sems[i], 1, 1); 
     if (!fork()) 
      child(&status[i], &sems[i]); 
    } 
    for (total = 0; total < 1000; sleep(1)) { 
     for (total = i = 0; i < 10; i++) { 
      sem_wait(&sems[i]); 
      total += status[i]; 
      sem_post(&sems[i]); 
     } 
     printf("%i/1000\n", total); 
    } 
    return 0; 
} 

エラーは、明確にするために省か。