2

g=(a+b)*(c+d)-(e/f)変数の任意の数値がハードコードされた式があるとします。fork() の仕組みをよりよく理解するために、複数の子プロセスを使用してこの式を計算したいと思います。

私の最初の試みは、子pid1、子pid2、子pid3(a + b)で計算し、プロセスで合計と減算を行うことでした。(c + d)(e / f)

残念なことに(a + b)、子プロセスpid1double expression1で行われた計算は、親プロセスの変数には影響しませんでした。その背後にある理由を考えます-各fork()は個別のメモリ空間を作成します。子プロセスが終了するとすぐに、その子プロセスで行われたすべての計算がなくなります。

このような状況で、あなたは通常何をしますか?(a + b)最初に計算するために、子プロセス内に fork() 子プロセスをネストできるのではないかと考えました。待ってください。それから(c + d); 待ってください(e / f); 待ってください最初の子は式全体を計算します。子リターン (0) ; が終了します。

しかし、この問題にはもっと簡単な解決策があると思いますよね?

4

4 に答える 4

3

の使用を主張する場合fork()は、子プロセスと共有メモリを使用する私の答えを次に示します。

ここでexit()は、システムが期待する方法で が使用されていることに注意してください: 子が正常に終了したかどうかを通知します。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>


struct shared{
    int a_b;
    int c_d;
    int e_f;
};
const int a=1,b=2,c=3,d=4,e=6,f=2;
const key_t key = 1234;
pid_t pab,pcd,pef;
void* shared_mem;

int main(){
    //Parent process create the shared memory 
    int shmid = shmget(key,sizeof(struct shared), 0666|IPC_CREAT);
    if(shmid == -1) exit(EXIT_FAILURE);

    //Fork child
    pab = fork();
    if(pab == 0){  
        //Inside process ab
        //attach to shared memory
        shared_mem = shmat(shmid,(void*) 0,0);
        if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
        struct shared* shared_data = (struct shared*) shared_mem;
        shared_data->a_b = a +b;

        //detach
        if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
        exit(EXIT_SUCCESS);
    }else {
        pcd = fork();
        if(pcd == 0){
            //Inside process cd
            //attach to shared memory
            shared_mem = shmat(shmid,(void*) 0,0);
            if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
            struct shared* shared_data = (struct shared*) shared_mem;
            shared_data->c_d = c+d;

            //detach
            if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
            exit(EXIT_SUCCESS);

        }else{
            pef = fork();
            if(pef == 0){
                //Inside process ef
                //attach to shared memory
                shared_mem = shmat(shmid,(void*) 0,0);
                if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
                struct shared* shared_data = (struct shared*) shared_mem;
                shared_data->e_f = e/f;

                //detach
                if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);

                exit(EXIT_SUCCESS);
            }
        }
    }

    //Wait child process termination
    int status_ab,status_cd,status_ef;
    waitpid(pab,&status_ab,0);
    waitpid(pcd,&status_cd,0);
    waitpid(pef,&status_ef,0);

    //Check if all child exited  normally
    if(!WIFEXITED(status_ab) || !WIFEXITED(status_cd)||!WIFEXITED(status_ef)){
        exit(EXIT_FAILURE);
    }

    //Parent attaches to memory 
    shared_mem = shmat(shmid,(void*) 0,0);
    if(shared_mem == (void*) -1) exit (EXIT_FAILURE);
    struct shared* shared_data = (struct shared*) shared_mem;

    //Calculate result
    int result = (shared_data->a_b)*(shared_data->c_d)-(shared_data->e_f);
    printf("Result is %d\n", result);

    //Parent detaches from shared memory and deletes
    if(shmdt(shared_mem) == -1) exit (EXIT_FAILURE);
    if(shmctl(shmid,IPC_RMID,0) == -1) exit(EXIT_FAILURE);

    return EXIT_SUCCESS;

}
于 2012-09-19T15:44:24.697 に答える
2

プロセスを fork() してから、戻り値を waitpid() します。

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

int main()
{
    //whatever values you like:
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    int e = 15;
    int f = 6;

    int a_plus_b_pid;
    int c_plus_d_pid;
    int e_div_f_pid;

    int a_plus_b;
    int c_plus_d;
    int e_div_f;

    a_plus_b_pid = fork();
    if(a_plus_b_pid)
    {
        c_plus_d_pid = fork();
        if(c_plus_d_pid)
        {
            e_div_f_pid = fork();
            if (e_div_f_pid)
            {
                //wait for our processes to exit, with our results, and stash the computed values.
                waitpid(a_plus_b_pid, &a_plus_b, 0);
                waitpid(c_plus_d_pid, &c_plus_d, 0);
                waitpid(e_div_f_pid, &e_div_f, 0);

                //The 8 least-significant bits carry info that we're not interested in here, so shift them out:
                a_plus_b >>= 8;
                c_plus_d >>= 8;
                e_div_f >>= 8;

                printf("%d %d %d %d\n", a_plus_b, c_plus_d, e_div_f, a_plus_b * c_plus_d - e_div_f);
            }
            else
            {
                exit (e/f);
            }
        }
        else
        {
            exit (c+d);
        }
    }
    else
    {
        exit (a+b);
    }
}
于 2012-09-19T00:59:37.887 に答える
1

これは、pthreads を使用したバージョンです。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>


volatile int a_b;
volatile int c_d;
volatile int e_f;
const int a=1,b=2,c=3,d=4,e=6,f=2;

void* calc_ab(void*);
void* calc_cd(void*);
void* calc_ef(void*);

int main(){
        pthread_t ab_thread, cd_thread, ef_thread;

        pthread_create(&ab_thread,NULL,calc_ab,NULL);
        pthread_create(&cd_thread,NULL,calc_cd,NULL);
        pthread_create(&ef_thread,NULL,calc_ef,NULL);
        pthread_join(ab_thread, NULL);
        pthread_join(cd_thread, NULL);
        pthread_join(ef_thread,NULL);
        int result = a_b*c_d-e_f;
        printf("Result is %d\n", result);

    return EXIT_SUCCESS;
}

void* calc_ab(void* arg){ a_b = a+b;pthread_exit(NULL);}
void* calc_cd(void* arg){ c_d = c+d;pthread_exit(NULL);}
void* calc_ef(void* arg){ e_f = e/f;pthread_exit(NULL);}

コンパイルするには、pthread にリンクする必要があります。 gcc pthread.c -lpthread -o teste

ノート

  • メインスレッドと子スレッドの間で共有される変数が宣言されていることに注意してくださいvolatile。これにより、コンパイラは、あるスレッドで行われた書き込みが他のスレッドに表示されないようにする可能性のあるメモリの最適化を実行できなくなります。
  • 各子スレッドは、異なる共有変数に書き込みます。同期を明示的に処理する必要がないように、コードをシンプルに保ちたいと考えました。
  • pthread_joinメインスレッドは、共有変数を変更したスレッドから戻った後にのみ、共有変数を読み取ります。ここでも、同期を明示的に処理する必要がないように、コードをシンプルに保ちたいと考えました。
于 2012-09-19T02:04:53.800 に答える
1

まず、任意の計算を行うためにプロセスはまったく必要ありません。luaなどのインタープリターを埋め込む方が簡単かもしれません。

もちろん、各プロセスには独自のアドレス空間があります。入力して、そのコマンドcat /proc/self/mapsを実行しているプロセスに関する情報を取得します。cat

プロセスがパイプを介して通信する方法を学習するためにプロセスを使用することを主張する場合は、いくつかのシステムコールを使用してコマンドを開始およびパイプするpopen(3)のようなものを使用できます。

char cmd[80];
int a, b, sum;
/// fill a & b
snprintf (cmd, sizeof(cmd), "echo $[%d + %d]", a, b);
FILE* pcmd = popen(cmd, "r");
if (fscanf (pcmd, "%d", &sum)>0) {
    // do something with sum
};
pclose(pcmd);

また、 Advanced Unix ProgrammingAdvanced Linux Programmingなどの優れた本を読む必要があります。本当のことは、fork(2)waitpid(2)execve(2)pipe(2)dup(2)などのシステムコールを理解することです.... syscalls (2)が何らかのコマンドによって行われることを理解することまたはプログラム、使用strace

于 2012-09-19T05:49:19.833 に答える