質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

5408閲覧

sem_getvalue()は成功するのにsem_wait()で失敗します

kutsulog

総合スコア985

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2014/11/23 12:45

スレッドの初期化処理完了を待つため、
sem_wait(&thread_inf[cnt].sem)を使っているのですが、
実行結果が失敗になります。(strerror(errno)の結果は[Invalid argument]になります)
確認のため、直前で
sem_getvalue(&thread_inf[cnt].sem, &val)を実行すると、
こちらは成功します。
(遅れて実行されるスレッド側のsem_post(&thread_inf[cnt].sem)も返り値は成功になります)

このthread_infはグローバル変数として宣言して使用しているのですが、
どこかまずいところがあるのでしょうか?

原因・対応がわかりましたら、回答お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

それぞれのthread_inf[cnt].semに対して、sem_initもしくはsem_openをする必要があるのではないでしょうか。

sem_initでの例を書いてみました。

(GCC 4.8.3 Cygwinを使用)

lang

1#include <stdio.h> 2#include <unistd.h> 3#include <errno.h> 4#include <pthread.h> 5#include <semaphore.h> 6 7sem_t sem; 8 9void *thread_f(); 10 11int main() 12{ 13 pthread_t th; 14 int shared; 15 unsigned int value; 16 int r; 17 18 shared = 1; 19 value = 0; 20 21 r = sem_init(&sem, shared, value); 22 printf("r=%d, err=%s\n", r, strerror(errno)); 23 24 r = sem_getvalue(&sem, &value); 25 printf("r=%d, err=%s\n", r, strerror(errno)); 26 27 if (pthread_create(&th, NULL, thread_f, (void *)NULL)) 28 { 29 printf("スレッドの生成に失敗\n"); 30 return 1; 31 } 32 33 printf("sem_wait\n"); 34 r = sem_wait(&sem); 35 printf("r=%d, err=%s\n", r, strerror(errno)); 36 37 return 0; 38} 39 40void *thread_f() { 41 sleep(5); 42 printf("sem_post\n"); 43 sem_post(&sem); 44 return (void *)NULL; 45}

投稿2014/11/25 05:28

argius

総合スコア9390

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kutsulog

2014/11/25 09:24

すみません 書き漏れていましたが、それぞれのthread_inf[cnt].semは sem_init( &thread_inf[cnt].sem, 0, 0 )で初期化しております。 このときの返値は ret:0/strerror(errno):Successになります。 sem_init( &thread_inf[cnt].sem, 1, 0 )も試してみましたが、 結果は変わらずでした。
argius

2014/11/25 10:24

そうですか... 上記のコードはこちらでは正しく動作しましたので、これとほぼ同じコードなのでしたら、プログラミング以外の問題の可能性もあるかも知れません。 本物のコードを提示するのは難しいと思いますので、もし、再現する最小限のコードを提示していただければ、コードが問題なのか、環境依存の問題なのかを切り分けられる可能性はあります。
kutsulog

2014/11/25 11:47

thread_infに使っている構造体の中身が typedef struct tagHOGE { BOOL a_flg;//Windowsから移植の都合でtypedef int BOOLしています BOOL b_flg;//Windowsから移植の都合でtypedef int BOOLしています //自作DBアクセスクラスです dbAccess *pDB; DWORD thread_no;//Windowsからの移植の都合でtypedef uint32_t DWORDしています char logfile[80+1]; pthread_t id; //各スレッドのid pthread_mutex_t mutex; // スレッド内調整用 sem_t sem1; // スレッド->メイン用 sem_t sem2; // メイン->スレッド用 }HOGE, *PHOGE; の構成だったのですが、 sem_t sem1とsemt_sem2をいちばん上に持って行ったところ sem_waitがret:0/strerror(errno):Successになりました。 他のメンバーの操作時にメモリ破壊をしているのかと、 sem1,sem2の位置を戻して他のメンバに対する処理をコメントアウトしたのですが、 この場合はret:-1/strerror(errno):Invalid argumentでした。 コメントアウト対象 (sem_init前) sprintf(thread_inf[cnt].logfile, "./TESTED_MODULE.LOG");//<-文字列そのままです (sem_init後) thread_inf[cnt].b_flg = DISABLE; /*#define DISABLE 0*/ pthread_mutex_init( &thread_inf[cnt].mutex, NULL ); thread_inf[cnt].thread_no = cnt + 1; thread_inf[cnt].pDB = new dbAccess; thread_inf[cnt].b_flg = ENABLE; /*#define ENABLE 1*/ (thread_inf[cnt].a_flgは今動かしている範囲では操作していません) 一応動くには動きましたが、どっかにしわ寄せが出そうで。。。
argius

2014/11/25 12:27

thread_inf自体はどのように宣言、初期化していますか? 配列サイズは固定ですか?
argius

2014/11/27 14:16

構造体の中が壊れていて、順番を変えたら発現しなくなったというのは、thread_infのアロケートに問題があるのかも知れません。 Windowsからに限らず、移植前はたまたま動いていたのが新しいOSに移植したら問題が顕在化したというケースはよくあります。
kutsulog

2014/12/07 02:09

thread_infの宣言は HOGE thread_inf[THREAD_MAX_SIZE]で宣言しています。 (reallocなどはしておらず、THREAD_MAX_SIZEは今のところ1です) 初期化は最初にmemset( &thread_inf[cnt], 0x00, sizeof(HOGE))した後 それぞれの値を設定して使っています。 セマフォ変数はもともとWindows時代は EventのPOST,WAITしていたところの代替で 今回の移植から使っています。
argius

2014/12/07 07:45

そうですか...他に考えられるとしたら、BlueMoonさんもおっしゃっていますが、セマフォ―関数とは無関係の何かしらの破壊的操作があるのでは?、くらいでしょうか。 地道にすべてのthread_infの操作前後で状態を見ていくしか思いつきません。 お役にたてずにすみません。
guest

0

thread_inf[cnt].semの値をログ出力などして、sem_init実行直後とsem_wait実行時で比較してみてはどうでしょうか。配列添え字のcntの値も気になります。

不要な説明かも知れませんがセマフォについてです。sem_はそのライブラリ関数になります。スレッドは並列実行されるので共通資源へのアクセス(共通の初期化処理、スレッド共通の変数へのアクセス等)に排他制御が必要になるのかと思います。

投稿2014/11/25 11:14

BlueMoon

総合スコア1339

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kutsulog

2014/12/07 01:57

init/wait/post それぞれの前(initは後)で値とアドレスをprintfして確認しましたが、 問題はありませんでした。 添字cntはforでそれぞれ初期化するために使っていますが、 for( int cnt = 0; cnt < 1; cnt++ )でも失敗しました。
BlueMoon

2014/12/07 04:18

別回答のコメントを見ますところ、構造体内のsem_tの位置を変えて成功したということであれば、構造体の他メンバを使用している処理が領域破壊している可能性が高いと思います。 思いつく調査方法は、関係処理をコメントアウトするなどして被疑部分を絞りこんでみる等です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問