2

共有メモリを介して、定義されたクラスのポインタを親とフォークされた子の間で共有しようとしています。

だから親のメインで私はポインタを作成します

mydata *p;
Reader::GetInstance()->Read(p, i+1);
        pid = fork();
        if (pid == -1){
            cout << "error on fork"<<endl;
        }else if (pid == 0){
            cout << "i will fork now" <<endl;
            const char * path = "./mydatamanager";
            execl (path, "-", (char *)0);
            break;
        }else {
            writer(shmid, p);
        }

作家はこれを含んでいます

void writer(int shmid , mydata * p)
{
    void *shmaddr;   
    shmaddr = shmat(shmid, (void *)0, 0);
    if((int)shmaddr == -1)
    {   
        perror("Error in attach in writer");
        exit(-1);
    }
    else
    {
        memcpy( shmaddr, p, sizeof(*p) );
    }   
}

私のデータは

    class mydara {
    public:
        int var1;
        int var2;
        int var3;
        int var4;
        int var5;
        int var6;
        char *var7;
mydata (int v2, int v3,char *v7, int v6){
        var2 = v2;
        var3 = v3;
        var7 =new char[128];
        strcpy(var7, v7);
        var6 = v6;
        var4 = 0;
        var5 = 0;
    }
    };

そしてmydatamanagerで私はこのポインターをこのように取得します

void reader(int shmid, mydata *& p)
{
    cout << "in reader" << endl;
    void *shmaddr;

      //sleep(3);

    shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
    if((int)shmaddr == -1)
    {   
        perror("Error in reader");
        exit(-1);
    }
    else
    {
        cout << "in else "<< endl;
        p = (mydata*) shmaddr;
        cout <<"shared memory address is " <<shmaddr <<endl;
        cout <<"var5 "<< p->var5<< endl;
        cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
        cout <<"var3 "<< p->var3<< endl;
        cout <<"var4 "<< p->var4<< endl;
        cout <<"var7 "<< p->var7<< endl; // the 
        //shmdt(shmaddr);
    }
}

およびmydatamanagermain:

int main()
{
    cout << "in main" <<endl;
    int shmid;
    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
    cout << "in advanced point" <<endl;
    sleep(1);
    mydata * p;
    reader (shmid, p);
    cout << p->var7 <<endl;
    return 0;
}

結果は常に0です。親と子を介してこのポインターを共有するにはどうすればよいですか。また、コードのどこに問題がありますか。

4

3 に答える 3

1

こんにちは私は数週間前にIPCタスクを持っていて、最終的にブーストを使用することにしました。

http://blog.wolfgang-vogl.com/?p=528

http://www.boost.org/doc/libs/1_36_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores

于 2012-12-22T02:13:25.037 に答える
1

まず第一に、あなたは何も同期していません。では、リーダーとライターのどちらが最初に実行されるかをどうやって知るのでしょうか。メモリは、新しく割り当てられたブロックでゼロにバインドされるため、結果としてゼロになります。

共有メモリは、少なくともライターが書き込みプロセス (少なくとも一部) を完了するまで、リーダーが読み取らないようにする必要があります。

クラスの共有に注意してください - 仮想関数を使用してはいけません。仮想関数を使用すると、ほとんどの場合、予想以上のことが起こるからです (クラッシュする可能性が最も高いですが、他のオプションが利用可能であり、特に快適なものはありません)。

于 2012-12-22T02:20:51.960 に答える
0

問題を処理する最も簡単な方法は、 のに親プロセスでセマフォを作成し、子プロセスに ( を実行する代わりに) 読み取りのforkにセマフォを取得させ、親プロセスが書き込みにセマフォを解放することです。sleep

まず、セマフォの ID を作成、破棄、取得する関数を次に示します。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>


int create_semaphore(const char *path, char id, int count){
    key_t k = ftok(path, id);
    semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
    semctl(semid, 0, SET_VAL, count);
    return semid;
}

int destroy_semaphore(int semid){
    semctl(semid, 0, IPC_RMID, 0);
}

int get_semaphore(const char *path, char id){
    key_t k = ftok(path, id);
    semid = semget(k, 1, 0600);
    return semid;
}

次に、それを取得するための関数と、それを解放するための別の関数が必要です。

void acquire_semaphore(int semid){
    sembuf op;
    op.sem_num = O;
    op.sem_op = -1;
    op.sem_flg = 0;
    semop(semid,&op,1);
}

void release_semaphore(int semid){
    sembuf op;
    op.sem_num = 0;
    op.sem_op = 1;
    op.sem_flg = 0;
    semop(semid,&op,1);
}

これらのボイラープレート関数を配置すると、プロセスを同期できるはずです。

そのため、セマフォを作成して識別するには、パスと一意の ID (単純な文字の形式) を提供する必要があります。ftok共有メモリ ID ( ) の作成に既に使用している場合shmidは、この考え方を理解する必要があります。それ以外の場合は、両方のプロセス内で両方の値が同じであることを確認してください。

ライター コードに、次の行を追加します。

 semid = create_semaphore(argv[0], 'S', 0);

行の直前にpid = fork();、セマフォの作成と取得を同時に行います。

次の行を追加します。

 release_semaphore(semid);

writer(shmid, mydata);セマフォを解放する命令の後。semidまた、スコープ内のどこかで宣言する必要があります。ライター プログラム パスを使用してセマフォを作成しました。これは、他のプロセスがパスを使用していないことを確認するための優れた方法です。唯一の問題は、リーダーが同じパスを使用することを確認する必要があることです。その値をリーダーのコードのどこかにハードコーディングするか、ライターからexeclパラメーターで渡すことができます (演習として残します)。

それがリーダーでわかっていると仮定すると、pathあとは次のようにセマフォを取得するだけです。

semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);

リーダーreader(shmid, mydata);の関数の行の前。main

他の投稿で述べたように、共有メモリ セグメントを介してクラス インスタンスを共有することは、通常、非常に悪い考えです。単純なデータを渡しstruct、リーダー側でオブジェクトを再構築する方がはるかに安全です (詳細については、ネットでシリアル化とマーシャリングを調べてください)。

この (テストされていない) コードに問題があるかどうか尋ねてください。

メリークリスマス!

于 2012-12-25T09:25:26.400 に答える