0

私が開発しているアプリケーション (Linux では、移植性を維持しようとしています) では、さまざまなプロセス (およびプロセス内のスレッド) 間でデータを共有するために共有メモリに切り替える必要があります。異なる子を生成する親プロセスがあります

たとえば、名前付きセマフォを使用して共有カウンターをインクリメントできるすべてのプロセスを取得する必要があります。

この場合、すべて問題ありません。

#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;

#define SEM_NAME "/mysem"
#define SM_NAME "tmp_sm.txt"

int main(){
    int fd, nloop, counter_reset;
    int *smo;
    sem_t *mutex;

    nloop = 100;
    counter_reset = 1000;

    if (fork() == 0) {
        /* child */
        /* create, initialize, and unlink semaphore */
        mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
        //sem_unlink(SEM_NAME);
        /* open file, initialize to 0, map into memory */
        fd = open(SM_NAME, O_RDWR | O_CREAT);
        smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        close(fd);
        /* INCREMENT */
        for (int i = 0; i < nloop; i++) {
            sem_wait(mutex);
            cout << "child: " << (*smo)++ << endl;
            if(*smo>=counter_reset){
                (*smo)=0;
            }
            sem_post(mutex);
        }
        exit(0);
    }
    /* parent */
    /* create, initialize, and unlink semaphore */
    mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
    sem_unlink(SEM_NAME);
    /* open file, initialize to 0, map into memory */
    fd = open(SM_NAME, O_RDWR | O_CREAT);
    smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    /* INCREMENT */
    for (int i = 0; i < nloop; i++) {
        sem_wait(mutex);
        cout << "parent: " << (*smo)++ << endl;
        if(*smo>=counter_reset){
            (*smo)=0;
        }
        sem_post(mutex);
    }
    exit(0);
}

これまでのところ、セマフォと共有カウンターの両方が問題なく (メモリ内の同じアドレス)、インクリメントとリセットが正常に機能しています。

プログラムは、子ソース コードを exec によって呼び出された新しいソース ファイルに移動するだけで失敗します。共有メモリと名前付きセマフォのアドレスが異なるため、インクリメントは失敗します。

なにか提案を?名前付きセマフォと名前付き共有メモリ (ファイルを使用) を使用して、同じポインター値を取得しようとしました。


アップデート:

Joachim Pileborg によって要求されたように、これは元のコードに対する「サーバー側」の改善点です。

...
if (fork() == 0) {
    /* child */
    /*spawn child by execl*/
    char cmd[] = "/path_to_bin/client";
    execl(cmd, cmd, (char *)0);
    cerr << "error while istantiating new process" << endl;
    exit(EXIT_FAILURE);
}
...

これが「クライアント」のソース コードです。

#include <sys/mman.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
using namespace std;

#define SEM_NAME "/mysem"
#define SM_NAME "tmp_ssm.txt"

int main(){
    int nloop, counter_reset;
    int *smo;
    sem_t *mutex;
    /* create, initialize, and unlink semaphore */
    mutex = sem_open(SEM_NAME, O_CREAT, 0777, 1);
    //sem_unlink(SEM_NAME);
    /* open file, initialize to 0, map into memory */
    int fd = open(SM_NAME, O_RDWR | O_CREAT);
    smo = (int *) mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    nloop=100;
    counter_reset=1000;
    /* INCREMENT */
    for (int i = 0; i < nloop; i++) {
        sem_wait(mutex);
        cout << "child: " << (*smo)++ << endl;
        if(*smo>=counter_reset){
            (*smo)=0;
        }
        sem_post(mutex);
    }
    exit(0);
}

このコードを実行すると、プロセスがブロック (デッドロック) され、無限に待機します。アドレスを見ると、典型的には次のようになります。

father semaphore: 0x7f2fe1813000
child semahpore: 0x7f0c4c793000
father shared memory: 0x7f2fe1811000
child shared memory: 0x7ffd175cb000

「sem_post」と「sem_wait」を削除しても問題ありませんが、インクリメント中に相互除外が必要です...

4

1 に答える 1

2

セマフォのリンクを解除しないでください。実際にセマフォを削除します。

sem_unlinkマニュアルページから:

sem_unlink()は、名前で参照される名前付きセマフォを削除します。セマフォ名はすぐに削除されます。セマフォを開いている他のすべてのプロセスがセマフォを閉じると、セマフォは破棄されます。

これは、親プロセスでセマフォを作成したら、すぐに削除することを意味します。子プロセスはセマフォを見つけることができず、代わりに新しいセマフォを作成します。

于 2013-02-12T11:23:44.933 に答える