2

いくつかのデバッグの問題を解決しようとしているときに、いくつかのprintf-s をコードに追加しました:

私はそのコードを使用しました:

struct PipeShm
{
    int init;
    sem_t sema;
        ...
        ...
}

struct PipeShm * sharedPipe = NULL;

機能2:

int func2()
{
if (!sharedPipe)
{

    int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0666);
    if (myFd == -1)
        error_out ("shm_open");

    // allocate some memory in the region in the size of the struct
    int retAlloc = ftruncate (myFd, sizeof * sharedPipe);
    if (retAlloc < 0)  // check if allocation failed
        error_out("ftruncate");

    // map the region and shared in with all the processes
    sharedPipe = mmap (NULL, sizeof * sharedPipe,PROT_READ | PROT_WRITE,MAP_SHARED , myFd, 0);

    if (sharedPipe == MAP_FAILED)  // check if the allocation failed
        error_out("mmap");

    // put initial value
    int value = -10;
    // get the value of the semaphore
    sem_getvalue(&sharedPipe->semaphore, &value);


    if (sharedPipe->init != TRUE) // get in here only if init is NOT TRUE !
    {
        if (!sem_init (&sharedPipe->semaphore, 1, 1)) // initialize the semaphore to 0
        {

            sharedPipe->init = TRUE;
            sharedPipe->flag = FALSE;
            sharedPipe->ptr1 = NULL;
            sharedPipe->ptr2 = NULL;
            sharedPipe->status1 = -10;
            sharedPipe->status2 = -10;
            sharedPipe->semaphoreFlag = FALSE;
            sharedPipe->currentPipeIndex = 0;
            printf("\nI'm inside the critical section! my init is: %d\n" , sharedPipe->init);

        }
        else
            perror ("shm_pipe_init");
        printf("\nI'm out the critical section! my init is: %d\n" , sharedPipe->init);

    }


}
return 1;   // always successful
}

そのメインで:

int main()

{
    int spd, pid, rb;
    char buff[4096];
    fork();
    func2();
    return 0;
}

そしてこれを得ました:

shm_pipe_mkfifo: ファイルが存在します

I'm inside the critical section! my init is: 1

I'm out the critical section! my init is: 1
Output:hello world!
I'm inside the critical section! my init is: 1

I'm out the critical section! my init is: 1

共有メモリがあまり共有されていないようですが、なぜですか?

  1. により、セグメントはすべてのプロセス間で共有されます。MAP_SHARED | MAP_ANONYMOUSでは、なぜ両方のプロセスが同じbeforeとのafter値を持つのでしょうか?

  2. プロセス間で共有されているにもかかわらず、各プロセスには独自のセマフォがあるようです。

ありがとう

4

2 に答える 2

4

MAP_ANONYMOUSフラグを使用するためmmapmyFd引数は無視され、各プロセスに1つずつ、相互に関係のない2つの独立した共有メモリチャンクが作成されます。

  MAP_ANONYMOUS
          The mapping is not backed by any file; its contents are initial‐
          ized to zero.  The fd and offset arguments are ignored; however,
          some implementations require fd to be -1  if  MAP_ANONYMOUS  (or
          MAP_ANON)  is specified, and portable applications should ensure
          this.  The use of MAP_ANONYMOUS in conjunction  with  MAP_SHARED
          is only supported on Linux since kernel 2.4.

削除するMAP_ANONYMOUSと、共有メモリチャンクは1つだけになりますが、を呼び出さないという問題がありsem_initます。NPTLを使用するLinuxでは、sem_tをすべて0バイト(ここでは初期状態)にクリアすることはsem_init(&sema, anything, 0);(NPTLはpsharedフラグを無視する)と同等であるため、実際に機能しますが、他のシステムには移植できません。

別の回答に対するKarolyのコメントによると、公募でのO_TRUNCによる競合状態もあります。最初のスレッドがすでにセマフォの変更を開始した後に2番目のスレッドが呼び出さopenれた場合、そのTRUNCはセマフォの状態を破壊します。おそらく最善の解決策は、共有メモリを作成、開き、mmapするコードを、forkを呼び出す前に呼び出される別の関数に移動することです。

編集

O_TRUNCの問題を修正するために、O_TRUNCを使用してshm_openを呼び出すプロセスを複数持つことはできません。ただし、O_TRUNCを削除しただけの場合は、起動時に問題が発生します。共有メモリオブジェクトが(プログラムの前回の実行から)すでに存在している場合、予測可能な状態ではない可能性があります。可能性としては、func2の先頭を分割することです。

main() {
    func1();
    fork();
    func2();
}

func1() {
    int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0666);
    if (myFd == -1)
        error_out ("shm_open");
    // allocate some memory in the region in the size of the struct
    int retAlloc = ftruncate (myFd, sizeof *sharedPipe);
    if (retAlloc < 0)  // check if allocation failed
        error_out("ftruncate");
    // map the region and shared in with all the processes
    sharedPipe = mmap (NULL, sizeof *sharedPipe, PROT_READ|PROT_WRITE, MAP_SHARED, myFd, 0);
    if (sharedPipe == MAP_FAILED)  // check if the allocation failed
        error_out("mmap");
}

func2() {
    // put initial value
    int value = -10;
    // get the value of the semaphore
    sem_getvalue(&sharedPipe->semaphore, &value);

    :

または、同じコードを保持して(O_TRUNCを削除するだけ)、フォークの前にクリーンアップを追加することもできます。

main() {
    shm_unlink("/myregion");
    fork();
    func2();

すべての場合において、プログラムの複数のコピーを同時に実行すると、問題が発生します。

于 2012-08-01T01:10:49.030 に答える
2

いくつかの考え...

  1. これは、POSIX セマフォがどのように機能するかについての根本的な誤解だと思います。sem_initまたはへの呼び出しが表示されませんsem_open。これまで以上に明示的に行わなければ、プロセス間でそれらを使用できないはずです。

  2. mmapLinux での の実装とMAP_ANONYMOUSこれにどのように影響するかについてはあまり詳しくありませんが、一般に、マップされた領域への書き込みは実際には瞬時に行うことはできません。linux.dieのマンページには次のように書かれています。

MAP_SHARED
このマッピングを共有します。マッピングの更新は、このファイルをマップする他のプロセスに表示され、基になるファイルに反映されます。msync(2) または munmap() が呼び出されるまで、ファイルは実際には更新されない場合があります。

この理由は、メモリ アクセスがページ フォールトにトラップされ、その時点でカーネルがファイル ディスクリプタからコンテンツを埋めてから、RAM に書き込みを実行させ、後でカーネルがフラッシュ バックするためです。ファイル記述子。

于 2012-07-31T23:15:02.740 に答える