ページ 11

スレッドが競合しない。

Posted: 2013年7月07日(日) 22:48
by 理澄
初めて利用させて頂きます。
スレッドを学習していたところ、出力結果がなぜそうなるのか理解できないため質問します。
今回組んだのは、スレッドを2つ用意し同じ変数にアクセスしてreadとwriteを行うようなものです。
コードは次のようになります。

コード:

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

static int count = 0;

void *threadA(void *arg)
{
	int i;
	int tmp;

	for(i = 0; i < 1000; i++){
		tmp = count;
		tmp = tmp + 1;
		count = tmp;
	}

	return NULL;
}

void *threadB(void *arg)
{
	int i;
	int tmp;

	for(i = 0; i < 1000; i++){
		tmp = count;
		tmp = tmp - 1;
		count = tmp;
	}

	return NULL;
}


int main()
{
	pthread_t a, b;

	pthread_create(&a,NULL,threadA,NULL);
	pthread_create(&b,NULL,threadB,NULL);

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

	printf("count = %d\n", count);

	return 0;
}
これを実行すると結果は0となります。片方が1000回インクリメントし、片方が1000回デクリメントするので当然と言えばそうなのですが、独立して動いてるはずのスレッドなのにかかわらずなぜインタリーブが起きないのでしょうか。A.read→B.read→A.write→B.writeとなる可能性だってあると思うのですが・・・
いろいろ調べると、同期プリミティブやセマフォ、条件変数など同期するための方法は出てきたのですが、自動で同期するような事は見つかりませんでした。
また、プリミティブ型への読み、書きは特定アーキテクチャ上では原子性が保証されること。などの情報は出て来ましたが、今回の場合はread→インクリメントorデクリメント→writeですし、ここまで原子性が保証されることは無いと思うのですがどうでしょう。

環境はホストがwindows7 64bit i5-2520mでvmwareのゲストがlinuxでコアの割り当ては2としています。cの実行はlinuxのgnome端末から行なっています。コンパイルにはgccを使用しています。

Cの理解度はほとんど文法などを知らない程度ですが、JavaやRubyなどは組めるのでプログラミング自体には慣れています。毎回やりたいことを検索し、でてきた情報を頼りに組んでいる感じなのでものすごい基礎の事を聞いているかもしれませんが、よろしくお願いします。
また、もう一つ別の質問があるのですが、別のトピックを立てたほうがよろしいのでしょうか?

Re: スレッドが競合しない。

Posted: 2013年7月07日(日) 22:57
by beatle
Mountain Lionで実行してみたところ,大体0になるのですが,-1000や1000というパターンもありました.
他のパターンもありました.
単に実行タイミングの影響でインターリーブが起こってない場合があるだけだと思います.

別の質問がほとんど関連性のないことならトピックを分けるべきです.
別質問は,この質問が解決状態になってからが良いと思います.

Re: スレッドが競合しない。

Posted: 2013年7月07日(日) 23:05
by 理澄
beatleさん返信ありがとうございました。
では、なぜ(高確率で)インタリーブが起きないのか、はタイミングで偶然大抵はインタリーブが起きないだけで、それをOSなどが自動で制御しているわけではないのでしょうか?
sched_yeild()を使えば明示的にインタリーブを起こすことができますが、使わないとめったにインタリーブが起きない理由が知りたいです。タイミングで偶然ならここまで偏らないと思うのですがどうでしょう。

Re: スレッドが競合しない。

Posted: 2013年7月07日(日) 23:20
by softya(ソフト屋)
間にIOなど入らずCPUが全力でぶんまわっているからだと思います。この場合、結果から推測するとvmwareだとスレッドが切り替わらないのではないでしょうか?
リアルコアで試すと結果が変わるような気がします。

【追記】 cygwinで試してみました。1000では少ないので1000000まで増やしています。
$ ./a.exe
count = 0
$ ./a.exe
count = 50382
$ ./a.exe
count = 20582
$ ./a.exe
count = 40547
$ ./a.exe
count = 11433

こんな感じになりました。

Re: スレッドが競合しない。

Posted: 2013年7月08日(月) 00:22
by 理澄
ソフト屋さん返信、追記までありがとうございます。
リアルコアと言われて、Visual studio2010を使ってコンパイルしようとしてPOSIXが使われている事を思い出し、どうしようかと迷っていました。sygwinを使うのが正解ですね・・・開発環境はいつもeclipseでJavaなのでこういう環境の問題に直面した時にどうするのか引き出しがありませんでした。勉強になります。
追記の結果を見ながら、自分でももう少し検証してみます。
暗示的に制御されているわけではないということがわかったので、解決とさせて頂きます。
返信してくださったbeatleさん、ソフト屋さん どうもありがとうございました。

もう一つ、こんどは環境は関係ない質問を別トピックで立てさせて頂きますので、よろしかったらそちらもお願いいたします。