ページ 11

子プロセスから共有メモリのアタッチ

Posted: 2011年4月03日(日) 15:53
by yu-ichi
お世話になります。
現在、Cygwin にて共有メモリについて学習しています。そこで質問なのですが、

親プロセスで新規作成した共有メモリに、子プロセスでアタッチし、値を設定、デタッチしようとしているのですが、
子プロセスでアタッチをすると異常終了してしまいます。

子プロセスからアタッチはできると思っているのですが、どこがいけないのでしょうか。
どうか、よろしくお願いします。

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>

int main(void)
{
int id;
int i;

/* 共有メモリ新規作成 */
id = shmget(IPC_PRIVATE, 512, 0666);
if(id == -1) {
perror("main-shmget ");
exit(-1);
}

/* 子プロセスを生成 */
if (fork() == 0) {

char *adr;

printf("子プロセス開始\n");

/* プロセスアドレス空間にアタッチ */
adr = (char *)shmat(id, NULL, 0);         // ★ ココでアタッチエラー
if(adr == (void *)-1) {
perror("子プロセス - shmat ");
exit(-1);
}

/* 共有メモリ・セグメントに文字列をコピー */
strcpy(adr, "Hello\n");

/* プロセスアドレス空間をデタッチ */
if(shmdt(adr) == -1) {
perror("子プロセス - shmdt ");
exit(-1);
}
printf("子プロセス終了\n");
exit(0);
}

/* 親プロセス-子の終了を待つ */
wait(NULL);

/* 共有メモリを破棄 */
if (shmctl(id, IPC_RMID, NULL) == -1){
perror("main-shmctl ");
exit(-1);
}

printf("親プロセス終了\n");
return 0;
}

Re: 子プロセスから共有メモリのアタッチ

Posted: 2011年4月03日(日) 20:04
by yu-ichi
コードが見づらくてすみません。書き直します。

コード:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>

int main(void)
{
    int id;
    int i;

    /* 共有メモリ新規作成 */
    id = shmget(IPC_PRIVATE, 512, 0666);
    if(id == -1) {
        perror("main-shmget ");
        exit(-1);
    }

    /* 子プロセスを生成 */
    if (fork() == 0) {

        char *adr;

        printf("子プロセス開始\n");

        /* プロセスアドレス空間にアタッチ */
        adr = (char *)shmat(id, NULL, 0);         // ★ ココでアタッチエラー
        if(adr == (void *)-1) {
            perror("子プロセス - shmat ");
            exit(-1);
        }

        /* 共有メモリ・セグメントに文字列をコピー */
        strcpy(adr, "Hello\n");

        /* プロセスアドレス空間をデタッチ */
        if(shmdt(adr) == -1) {
            perror("子プロセス - shmdt ");
            exit(-1);
        }
        printf("子プロセス終了\n");
        exit(0);
    }

    /* 親プロセス-子の終了を待つ */
    wait(NULL);

    /* 共有メモリを破棄 */
    if (shmctl(id, IPC_RMID, NULL) == -1){
        perror("main-shmctl ");
        exit(-1);
    }

    printf("親プロセス終了\n");
    return 0;
}
よろしくお願いします。

Re: 子プロセスから共有メモリのアタッチ

Posted: 2011年4月04日(月) 18:05
by ISLe
Bad System Callは回避できているということですよね。

未確認ですが検索して見付けたページを紹介します。
http://d.hatena.ne.jp/haradats/20060504/p2
要約すると、
  1. CYGWIN環境変数にserverを追加
  2. cygserver-configコマンドを実行してウインドウズにサービスを登録
  3. net start cygserverもしくはcygrunsrv -S cygserverのコマンドラインでコマンドを実行してサービスを開始
とすると動作するようですが。
最後に念のためウインドウズを再起動したほうが良いでしょう。

(追記)
サービスの登録・起動の際は管理者権限が必要だそうです。

Re: 子プロセスから共有メモリのアタッチ

Posted: 2011年4月06日(水) 17:45
by yu-ichi
どうもありがとうございます。

cygserver ですが、下記の方法でcygserverを起動してから実行しています。

1. $ cygserver-config を実行
2. $ /usr/sbin/cygserver & を実行

ps でcygserverが動作していることを確認
  3440 2396 3440 4188 0 1000 17:34:51 /usr/sbin/cygserver

その後、実行すると28行目でアタッチエラーとなり、その後cygserverが落ちてしまいます。

エラーは以下の通りです。
$ ./s
子プロセス開始
0 [unknown (0xF50)] cygserver 5472 exception::handle: Error while dumping state (probably corr
upted stack)
子プロセス - shmat : Invalid argument
0 [main] s 5560 transport_layer_pipes::connect: lost connection to cygserver, error = 2
0 [main] s 5560 transport_layer_pipes::connect: lost connection to cygserver, error = 2
[1]+ Segmentation fault (core dumped) /usr/sbin/cygserver
Bad system call

Re: 子プロセスから共有メモリのアタッチ

Posted: 2011年4月07日(木) 03:10
by ISLe
とりあえずcygserverは直接起動するのではなく、ウインドウズのサービスとして起動してください。
cygserverの例外ハンドルのエラーとセグメンテーション違反はそれで消えます。

動作確認したところ、それでもshmatでコネクションをロストするというエラーは発生するので調べてみました。

Cygwinの仕様で、forkした子プロセスでアタッチ(shmat)/デタッチ(shmdt)することはできないようです。
ウインドウズではスレッドで実装されているためかと思います。

http://linuxgcc.sytes.net/sys013.php
↑こちらのページによると、親プロセス側でアタッチして得たポインタをそのままforkした子プロセスで共有メモリのアクセスに使えるようです。
こちらの方法はCygwinとUbuntuの両方で正常動作を確認できました。