pthread_createの引数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
理澄

pthread_createの引数について

#1

投稿記事 by 理澄 » 12年前

連続で失礼します。
おそらくは、アドレスやポインターを理解していないのだと思いますが、次の2つのコードの結果がなぜ異なるのかが理解できません。

コード:

#include <stdio.h>
#include <pthread.h>

void *thread(void *arg)
{
	for(;;){
		printf("Thread (%d)\n", *(int*)arg);
		sleep(1);
	}
	return NULL;
}

int main(void)
{
	pthread_t a, b;
	int arg_a = 0, arg_b = 1;

	pthread_create(&a,NULL,thread,&arg_a);
	pthread_create(&b,NULL,thread,&arg_b);

	pthread_join(a, NULL);
	pthread_join(b, NULL);

	return 0;
}

コード:

#include <stdio.h>
#include <pthread.h>

void *thread(void *arg)
{
	for(;;){
	 	printf("Thread (%d)\n", *(int*)arg);
		sleep(1);
	}
	return NULL;
}

int main(void)
{
	pthread_t t[2];
	int i;

	for(i = 0;i < 2; i++)
		pthread_create(&t[i],NULL,thread,&i);

	for(i = 0;i < 2; i++)
		pthread_join(t[i],NULL);

	return 0;
}
の2つです。やっている内容は引数をint*にキャストして表示するだけだと思うのですが・・・
なぜ異なる結果となるのか教えて下さい。
それと不明瞭な事がいくつかあります。
引数をvoid *argとはせずに初めからint * argとしない理由はなんでしょう。
以下のコードは1つ目のコードをintから文字列対応させろという演習なのですが、やり方はあっているのでしょうか、出力結果は期待していたものを得ることができましたが、引数の&を消したりint→doubleにするときにはしなかった操作をしたので不安です。

コード:

#include <stdio.h>
#include <pthread.h>

void *thread(void *arg)
{
	for(;;){
	  printf("Thread (%s)\n", (char*)arg);
		sleep(1);
	}
	return NULL;
}

int main(void)
{
	pthread_t a, b;
	char *arg_a, *arg_b;
	arg_a="this is a";
	arg_b="this is b";

	pthread_create(&a,NULL,thread,arg_a);
	pthread_create(&b,NULL,thread,arg_b);

	pthread_join(a, NULL);
	pthread_join(b, NULL);

	return 0;
}

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: pthread_createの引数について

#2

投稿記事 by へにっくす » 12年前

理澄 さんが書きました:おそらくは、アドレスやポインターを理解していないのだと思いますが、次の2つのコードの結果がなぜ異なるのかが理解できません。
アドレスやポインターは理解しているように見えますが?スレッド動作について理解していないのですよね。
それは一つ目と二つ目はそれぞれ一定の結果となることを確認した上でのことですか?
一つ目を何回かやってみてください。常に同じ結果になりますか?
同様に二つ目も。
おそらく実行するごとに違ってくるのではないかと思うのですが。。
だから比較しても意味がありません。
理澄 さんが書きました:引数をvoid *argとはせずに初めからint * argとしない理由はなんでしょう。
それは作った人にしか分かりませんよ?
理澄 さんが書きました:以下のコードは1つ目のコードをintから文字列対応させろという演習なのですが、やり方はあっているのでしょうか
あっていると思います。文字列がちゃんと出たのですよね?
written by へにっくす

理澄

Re: pthread_createの引数について

#3

投稿記事 by 理澄 » 12年前

へにっくすさん返信ありがとうございます。
質問の答えですが、2つとも結果は常に同じになります。与えられた引数を出力するだけなので、
1つ目は
Thread(0)
Thread(1)
の無限ループ
2つ目は
Thread(0)
Thread(0)
の無限ループとなっています。
ここで自分がわからないことは、インタリーブが起きて0 1 1 0の順番になることではなく、2つ目がなぜ同じ0と1を引数にしているのに、0 0となっているのかです。
質問の具体性が足りていなくて申し訳ありませんでした。
3つ目に関しては、出力は期待通りなので大丈夫そうですね、ありがとうございます。

たろ

Re: pthread_createの引数について

#4

投稿記事 by たろ » 12年前

コード見ただけで実行していませんが・・、
2つ目のプログラムは、どちらのスレッドもおなじ変数 i を参照しているので、出力はおなじ値になっても別に不思議ではないとして、
さらに「0 0」になるのは、i が 0 なんでしょう。ということで、ひょっとして、pthread_join() の一発目が返ってこない(ブロックしている)
ので i が 0 のまま変わらないとか・・?どうでしょうか。

理澄

Re: pthread_createの引数について

#5

投稿記事 by 理澄 » 12年前

たろさん返信ありがとうございます。
ご指摘の箇所を調べてみましたら、1回めのjoinが本当に帰ってきていませんでした!
今まではjoinをfor文ではなく、縦に並べて使っていて、正常だったのでまさかここで止まっているとは予想外でした。
joinがブロックされていることはわかったのですが、なぜfor文にしただけなのにブロックされてしまうのでしょうか。
と、検証しながら書いていると縦に並べてもできないことがわかりました。
すると原因は、配列ということになると思いますが、なぜでしょうか?
自分は配列の1番目の要素のスレッドにjoinをしたと思っているのですが、もしかして配列自体にjoinのような事態になっているような気がします。
配列にいれたスレッドにはjoinできないんでしょうか?

たろ

Re: pthread_createの引数について

#6

投稿記事 by たろ » 12年前

pthread_join がブロックするのは、スレッドが for(;;) の無限ループに入ったまま終了しないからじゃないでしょうか・・?
スレッド関数を適当なタイミングで return させれば、joinが戻るようになるかなと思います。

#スレッド終了は pthread_exit でもよいかもしれません。すみませんあまり詳しくなくて。

配列の使い方は特に問題ないと思います。

理澄

Re: pthread_createの引数について

#7

投稿記事 by 理澄 » 12年前

まさか投稿時間が、返信ページを開いた時間だとは思いませんでした。
検証しながら、返信を書いていたため、たろさんの最後の書き込みの時系列が逆になってしまいました。
たろさんのおかげで全て理解できたので、すごい感謝しています。ありがとうございました。

理澄

Re: pthread_createの引数について

#8

投稿記事 by 理澄 » 12年前

あーすいません、意味不明な返信になってしまいました。
返信ページを長い間開きすぎていて、投稿したつもりがタイムアウトで無効にされていただけでした。
自分はiのポインタが引数に渡されている事を理解せずにやっていたことが、敗因でした。
値の0,1が渡されているのではなく、0,1を代入した変数iのアドレスを渡しているため、どこのiも参照が同じになり、さらにjoinのfor文で0が代入され、引数のスレッドが無限ループなのでその時点でiは不変となる。
ということですよね。
いつもはJavaでforのブロックの中のみがスコープのような書き方をするので、まさかintのiが参照されているなんて思いもしませんでした・・・
1時間以上悩んで、やっとたろさんの言葉の意味が理解できました。
今ではすっきりしていい気分です。本当にありがとうございました。

たろ

Re: pthread_createの引数について

#9

投稿記事 by たろ » 12年前

お役に立ててよかったです。プログラムの挙動の説明、私の考えとおなじです。
私もスレッドの挙動をテストしたい時はこんな感じのコードを書いたことがあるので、よい復習になりました(^^)

YuO
記事: 947
登録日時: 15年前
住所: 東京都世田谷区

Re: pthread_createの引数について

#10

投稿記事 by YuO » 12年前

解決とありますが,きっちりとした回答がついていない点がありましたので。
理澄 さんが書きました:引数をvoid *argとはせずに初めからint * argとしない理由はなんでしょう。
pthread_createの第3引数が,void * (*)(void *)型だからです。
で,普段void *と任意の型のポインタを自由に変換できるのは,コンパイラが「変換が必要である」ことを知っていて,コンパイラが変換を自動的に行ってくれているからです。
最近の処理系では,ポインタ型の内部表現はどれも同じでしょうけれども,過去には内部表現の異なる処理系も存在しましたし,標準もそれを許しています。

pthread_createの中で,スレッドの開始コードには以下のようなコードがあると思われます。

コード:

void * retval = start_routine(arg);
この時点で,argの型はvoid *,start_routineの引数の型もvoid *です。
このため,実はコールバックされる関数の引数の型はint *でした,という場合,void *とint *の間で実表現が異なれば,コールバックされる関数側で正しく間接参照できなくなります。

次に,POSIXが引数をvoid *型としたのは,汎用性のためでしょう。
int *型とした場合,スレッドの開始関数に渡すことのできる引数はint型のオブジェクトへのポインタか,int型の配列だけになります。
void *型であれば,引数は任意のオブジェクトへのポインタが渡せます。
# 少なくとも,関数宣言はそのように宣言しているとみなされます。
後者であれば,int型のオブジェクトへのポインタも渡せますが,前者では,例えばlong型のオブジェクトへのポインタを渡すことが正しくないように読み取れてしまいます。

閉鎖

“C言語何でも質問掲示板” へ戻る