こんにちは。今日も並列的なインドリです♪
突然ですが今日も並列処理について囀ります♪
並列処理の一番難しいところは、実行順序が決まっておらず、何時他の処理からの影響を受けるか分からない点です。
例えば、
flag = true; //※flag変数は外部から変えられると仮定する
if ( flag == true ) {
//ここに来るよね?
} else {
//ここに来る事はないはずだけど・・・
}
このプログラムでも、false時の処理がされる場合があります。逐次処理に慣れきった人は、ここで足元をすくわれます。
ですが、複数の処理を並列的に行っているのですから、flagを変える処理が割り込めば、falseになる可能性があるのです。
こんな単純な処理ですら、逐次処理の感覚でしていれば罠にはまります。
しかもこの問題は、短いサンプルでは表面化しません。
従って、逐次処理では短いプログラムを実行し、エラーの有無を確かめる事は有用ですが、並列処理では通用しません。
では、どうすればいいのかと言いますと、純粋に知識と経験から判断するしかありません。
並列処理の知識があれば、先ほどのサンプルの問題に気が付きます。
といっても、本来技術者は自分のプログラムを把握するべきですから、知識と経験が必要なのは当然です。
とはいえ、問題がないわけではありません。
それは、テストプログラムが組みにくい点です。
短いテストプログラムでテストをパスしても、実稼働した時に問題が発生する可能性があります。
これを防ぐには、全技術者が知識を高める努力をし、コードレビューをするしかありません。
しかしながら、それだけでは工学的に問題を解決したとは言い切れないと考えます。
理想的には、flagをfalseに設定する様な賢いテストプログラムが必要です。
これはチェックツールである程度可能ですが、難しいケースとなると不十分だと感じます。
テスト用の人工知能を組み込む必要性があります。
さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。
それ故、スレッドローカルストレージが多用されているわけです。
この答えはなれない人にとっては難しく感じるかもしれません。
ですが、オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。
それを実践していれば、こういう風な問題に遭遇する可能性が低くなります。
そういった事からオブジェクト指向を実践する事は、並列処理にとっても有益です。
情報処理技術は全てが結びついており、不必要な知識なんてないのです。
この春入社する新人さんはよく学び、よく遊びましょう♪
面白いですよー♪
テーマ : プログラミング
ジャンル : コンピュータ
>flag = true; //※flag変数は外部から変えられると仮定する
>その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
>このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低>下させるので、ローカル変数にする方です。
ローカル変数にするということは、最初の仮定が成り立たなくなるよ。
>口うるさく「変数を外部に出すな」
これには同意。
> >flag = true; //※flag変数は外部から変えられると仮定する
>
> >その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
> >このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低>下させるので、ローカル変数にする方です。
>
> ローカル変数にするということは、最初の仮定が成り立たなくなるよ。
うーん。どうしてそう考えるのかな?
問題があるプログラムを提示して、その問題を解決するために、ローカル変数にするべきだと言っているわけです。
並列処理では、実行順序が決まっておらず、何時他の処理からの影響を受けるか分かりません。
従って、変数を下手に外部に出すとエラーの元になります。
それを理解せず、逐次処理の感覚で短いサンプルを作って、
「動いているから正しい」と言い張る人が居ます。
しかしそれは、ただ単にサンプルが短すぎて、他のスレッドからの影響を受けていないだけであって、行ってはならない致命的な誤りです。
無闇に変数を外部に出してはなりません。
それは、何も並列処理に限った話ではなく、オブジェクト指向でも言われている事です。
並列処理を難しいと拒否する人もいますが、並列処理の考え方も無から生じたわけではなく、
元からある概念の積み重ねで出来ています。
それ故、身構えずに気楽に広く学べばいいわけです。
>問題があるプログラムを提示して、その問題を解決するために、ローカル変数にするべきだと言っているわけです。
その場合、外部で使っていた方は「未定義」になってしまいますが?
> >問題があるプログラムを提示して、その問題を解決するために、ローカル変数にするべきだと言っているわけです。
>
> その場合、外部で使っていた方は「未定義」になってしまいますが?
普通はアクセス範囲を局所的にする事を狙います。
だから、設計を見直せと言っているわけです。
というか、未定義ではなくて、コンパイルエラーが出るよ。
変数のアクセス範囲を慎重に見極めましょう。
基本的に極力アクセス範囲を狭くする方がいいです。
逐次処理の感覚で、なんとなく変数を扱っていると、並列処理をするのは困難になります。
横槍ごめん。
>普通はアクセス範囲を局所的にする事を狙います。
>だから、設計を見直せと言っているわけです。
あるまじろさんは設計上、アクセス範囲を小さくしていいのか?という事を聞いているんだと思います。
たぶん元のサンプルにあるコメント
> //※flag変数は外部から変えられると仮定する
が本来の仕様なのか、想定外の動作なのかがはっきりしない所為でしょう。
本来の仕様:
タイミングの問題を別にすれば、外部から flag の値を変えられる事自体は正しい動作
想定外の動作:
flag の値は本来外部から変えられてはいけないのに、何らかの理由で外部から変えられてしまっていた
記事中のサンプルはどちらのつもりで提示したサンプルなんでしょう?
> 横槍ごめん。
>
> >普通はアクセス範囲を局所的にする事を狙います。
> >だから、設計を見直せと言っているわけです。
>
> あるまじろさんは設計上、アクセス範囲を小さくしていいのか?という事を聞いているんだと思います。
> たぶん元のサンプルにあるコメント
>
> > //※flag変数は外部から変えられると仮定する
>
> が本来の仕様なのか、想定外の動作なのかがはっきりしない所為でしょう。
>
> 本来の仕様:
> タイミングの問題を別にすれば、外部から flag の値を変えられる事自体は正しい動作
>
> 想定外の動作:
> flag の値は本来外部から変えられてはいけないのに、何らかの理由で外部から変えられてしまっていた
>
> 記事中のサンプルはどちらのつもりで提示したサンプルなんでしょう?
どちらも想定して書いています。
だから、「ローカル変数にする」か「ロックを掛ける」の2つの答えを用意しています。
もし片一方だけ想定するのであれば、両方書きません。
ただし、大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。
というのも、複数の処理が同時にそのオブジェクトにアクセスして、ステータスを変えてしまうからです。
そうなると、予期しない動作を起こすでしょう。
よく読めばわかると思いますが、無闇に変数を外部に出すなと言っているわけですから、どちらかというと、出したら駄目な例なのです。
変数を外部に出してもよい例を出して出すなという人はいません。
それに加えて、慎重に変数のアクセス範囲を見極めるように言っているわけですから、
その都度判断をすればいいという事です。
無闇に変数をローカルにするとか、無闇にロックを掛けるのは駄目なのです。
他にも色々ありますが、先ずはこの2つを理解しないと先に進めないでしょう。
念のために付け加えて置きますが、よいオブジェクト指向をしていれば、意味もなく変数を外部に出すという事はしないはずです。
何故ならば、カプセル化の原則は、データの隠ぺいだけではなく、
再利用の為に余計な情報を外部に出さない事を意味しているからです。
つまり、並列処理をするからと言ってオブジェクト指向をないがしろにしてもいいというわけではなく、並列処理とオブジェクト指向の知識は両方いります。
ちなみに、flagとかで動作を変えるぐらいならば、オブジェクト指向では通常、違うメソッドにするでしょう。
状況によって対処法は異なりますが、継承やオーバーライドを駆使する事になるでしょう。
まれにフラグを使わないと駄目な処理もありますが、大体はフラグを多用し始めたら危険な兆候であり、リファクタリングの帽子をかぶる事になります。
>> 本来の仕様:
>> タイミングの問題を別にすれば、外部から flag の値を変えられる事自体は正しい動作
>> 想定外の動作:
>> flag の値は本来外部から変えられてはいけないのに、何らかの理由で外部から変えられてしまっていた
>> 記事中のサンプルはどちらのつもりで提示したサンプルなんでしょう?
>どちらも想定して書いています。
>だから、「ローカル変数にする」か「ロックを掛ける」の2つの答えを用意しています。
どちらも想定、ですか...正直予想外でした。
変数のアクセス範囲は並列処理でなくても考える事だし、並列処理の話でもあるので基本的には仕様かと考えていました。
>もし片一方だけ想定するのであれば、両方書きません。
...何の前置きもなく単に両方の答えを書いただけで、私が例示した二種類のケースをどちらも想定していると考えられる技術者はほぼ皆無だと思いますよ...
>ただし、大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。
>というのも、複数の処理が同時にそのオブジェクトにアクセスして、ステータスを変えてしまうからです。
>そうなると、予期しない動作を起こすでしょう。
え、並列処理時に flag のような外部からも操作できる変数を安全にアクセスする為に使うのがロックですよね?
で、ご自身でも「ロックを掛ける」のは答えの一つだとかいていらっしゃいますよね?
なのに「大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。」て続けられても、何を言いたいのかさっぱり分かりません。
いくらロックを掛けてもステータスが変わるタイミングは予期できないから、
「大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は (ロックを掛けても期待通りの順番では) 動作しません。」という事?
それともロックを掛けないと安全には動作させられないから
「大概flagの様なステータス系変数が外部からアクセスされる時は、(ロックを掛けないと) 並列処理は動作しません。」という事?
それともそれ以外の何か?
>無闇に変数をローカルにするとか、無闇にロックを掛けるのは駄目なのです。
「無闇にロックを掛けるのはダメ」には賛成です。
>念のために付け加えて置きますが、よいオブジェクト指向をしていれば、意味もなく変数を外部に出すという事はしないはずです。
ええと、並列処理なら並列処理に絞って話をしていただけると助かります。
オブジェクト指向にしても変数のアクセス範囲にしても、別に並列処理に特有の考え方ではありませんし、あれもこれもと欲張ると話の焦点がボケてしまいますので。
うーん。どこが分からないのだろう?
正直言って、何が分からなくてそんな事を言っているのかが分かりません。
記事とコメントを読んでほしいな。記事とコメントに書いてある事を何度も問われても・・・
これは極めて単純な話しで、並列処理の原則は、変数のアクセス範囲を極力狭くする事です。
ロックを掛けるのはその後です。
何でもロックすればいいというものではありません。
それと、オブジェクト指向の知識も必要です。
オブジェクト指向言語(大概がそう)で並列処理をする場合、当然オブジェクト指向についても考えなくてはなりません。
並列処理だからと言って、オブジェクト指向的におかしな事をするのは問題外です。
オブジェクト指向がちゃんとした上で、並列処理をしないと駄目です。
並列処理の基礎的を解説するのが目的だから、極めて単純な事しか書いていないんだけどな・・・
問題あるプログラムだと書いてあるのも関わらず、解決するのが矛盾しているとか言われると、読んでいないとしか思えません。
予め忠告しておきますが、あまりにも記事とコメントを読まないのであれば、コメントを拒否しますよ。
コメントと記事を読まないのであれば、会話は不可能だと思います。
まだ分かってもらえないようなので、超簡単に書きます。
一、変数はなるべく狭い範囲に限定するべし。
一、ロックは最後の手段。
一、オブジェクト指向を学ぼう
一、並列処理も学ぼう
これでどうだろうか?
これでも分からないと言われたら正直言って無理です。
国語とプログラミングの基礎から学ぶ事をお勧めします。
>うーん。どこが分からないのだろう?
>正直言って、何が分からなくてそんな事を言っているのかが分かりません。
> (snip)
う〜ん...本文やコメントを何度読み返しても分からないからコメント書いてるんですけどね...まぁいいや。
とりあえず何が分からないかについて最初から説明させてもらいます。
長文ですがご容赦ください。
まず最初に提示されたサンプルを変数のアクセス範囲を分かるように変更します。
例えばこんな感じ。
----
bool flag;
void SampleFunc()
{
flag = true; //※flag変数は外部から変えられると仮定する
//← ここで別スレッドが割り込んでflag変えちゃうかも?
if ( flag == true ) {
//ここに来るよね?
} else {
//ここに来る事はないはずだけど・・・
}
}
----
で、この並列処理では期待通りに動作しないサンプルに対し、正しく動作させる為には
1)ローカル変数にする
2)ロックを掛ける
のどちらかが必要である、という答えが本文で提示されています。
更に 2 種類の答えを併記したのは flag が外部から操作されるのが想定外の動作である時と、正しい動作である時をどちらも想定しているからだ、とコメントを頂きました。
それはすなわち
1)ローカル変数にする ← flag が外部から操作されるのが想定外の時
2)ロックを掛ける ← flag が外部から操作されるのが正しい動作である時
という事だろうと考えます。
これらを踏まえた上で、先のサンプルをそれぞれ提示された回答で修正します。
多分こんな感じでしょうか。
回答1)ローカル変数にする場合
----
//bool flag;
void SampleFunc()
{
bool flag;
flag = true; //※flag変数は外部から変えられると仮定する
// ↑ ローカル変数にしたから外部から変えられなくなって安心♪
if ( flag == true ) {
//ここに来るよ
} else {
//ここに来る事はない
}
}
----
回答2)ロックを掛ける場合
# ロック範囲が広すぎる件はスルーの方向で。
----
bool flag; //flag変数は外部変数のまま
void SampleFunc()
{
thread_lock(); //ここでロック。ただし関数名は適当
flag = true; //※flag変数は外部から変えられると仮定する
// ←ロック掛けたからここで割り込まれる事がなくなって安心♪
if ( flag == true ) {
//ここに来るよ
} else {
//ここに来る事はない
}
thread_unlock(); //ここでロック解除。ただし関数名は適当
}
----
# 以下は回答2)で想定したロックを掛ける場合のコードが正しいという前提。
これらはどちらも本文中で提示された答えを踏まえて修正したコード、すなわちどちらも「並列処理が動作する」コードである筈です。
しかしながら回答2)をみると、flag は外部からアクセス可能なままですよね。
故にこのケースではコメントの中にある
>大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。
を額面どおりに受け取った場合、ロックを掛けているにも関わらず「並列処理は動作しない」事になります。
しかし本文は元よりコメントでも「ロックは最終手段」とあるように、並列処理においてロックが有用である事は度々言及されています。
今現在もっとも分からないのはこの部分なのです。
要するに一エントリの中で
本文 :ロックを掛ければ並列処理は動作する
コメント:ロックを掛けても並列処理は動作しない
と書かれているように読めてしまうのだけれど、そんな矛盾はありえないから、きっとこちらが何かを誤解しているか、もしかしたら何か必要な言葉が書かれていないか、という状態なのでしょう。
ただそれを確認したいだけなんです。
オブジェクト指向的に正しくないといけない、とか、変数のアクセス範囲を狭めればいい とか、そんな次元の話は始めからしていないんですよ。
もちろん「回答2)ロックを使用する場合」で私が想定したコードは、貴方の想定しているコードとは違うのかもしれません。
そうであるなら「変数 flag は外部からアクセスされる仕様である」という前提で貴方が想定しているコードを提示していただけないでしょうか。
そのコードを元にして全体を最初から考え直したいと思います。
> しかし本文は元よりコメントでも「ロックは最終手段」とあるように、並列処理においてロックが有用である事は度々言及されています。
> 今現在もっとも分からないのはこの部分なのです。
>
> 要するに一エントリの中で
>
> 本文 :ロックを掛ければ並列処理は動作する
> コメント:ロックを掛けても並列処理は動作しない
>
> と書かれているように読めてしまうのだけれど、そんな矛盾はありえないから、きっとこちらが何かを誤解しているか、もしかしたら何か必要な言葉が書かれていないか、という状態なのでしょう。
> ただそれを確認したいだけなんです。
正しくロックをかけた場合、動作するのに決まっています。
そうでないならば、問題解決法として提示しません。
ようは変数で処理を切り替える状態はおかしいので、かなりの確率でオブジェクト指向設計的に間違っているという点です。
設計を見直し、それでも正しいのならばロックを掛けるしかありません。
if( 変数をローカルに出来るか? ) {
//リファクタリング開始
//ローカルに変更
//ロックを掛ける必要はない
} else {
//ロックを掛けよう
}
> オブジェクト指向的に正しくないといけない、とか、変数のアクセス範囲を狭めればいい とか、そんな次元の話は始めからしていないんですよ。
>
最初からそんな話ししかしていませんが・・・
だから何故分からないのかと不思議に思っていました。
問題を提示して、その解決法を書いているにも関わらず、解決すること自体が矛盾しているとか意味不明な事を言われて困っております。
※あるまじろさんはいつもこんな調子です。何時も一部の文を切り抜いて曲解します。
ですからこちらとしては、荒らしか本当に文章が読めないのかのうちどちらかしかないと考えております。
とにかく、この基礎を分からなければ、並列処理は理解できません。
私が言っているのは、初めに変数の範囲をよく考えて、それでも駄目ならばロックしかないと言う事です。
>
> もちろん「回答2)ロックを使用する場合」で私が想定したコードは、貴方の想定しているコードとは違うのかもしれません。
> そうであるなら「変数 flag は外部からアクセスされる仕様である」という前提で貴方が想定しているコードを提示していただけないでしょうか。
> そのコードを元にして全体を最初から考え直したいと思います。
大丈夫です私の頭の中のコードと一致する必要はありません。
ただ単に、変数の範囲を考えることと最悪の場合ロックを掛ける事しか言っておりません。
ロックはデッドロックなどのバグを生みますし、パフォーマンスを低下させますので、慎重にせねばなりません。
そもそも、コードが云々というレベルではありません。
実務では数十万行になるわけですから、この単純な事が如何に問題になるか分かりますよね。
>正しくロックをかけた場合、動作するのに決まっています。
>そうでないならば、問題解決法として提示しません。
...つまり私が理解できなかった下記の文は
>大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。
↓
>大概flagの様なステータス系変数が外部からアクセスされる時は、“ロックを掛けないと”並列処理は動作しません。
と言う解釈でよいという事ですね。
それぞれの解決策がどういうケースを想定しているかを明言した直後に、何の前置きもなく解決策を講じていないケースに言及すると思ってなかったので、意味が理解できませんでした。
>> オブジェクト指向的に正しくないといけない、とか、変数のアクセス範囲を狭めればいい とか、そんな次元の話は始めからしていないんですよ。
>最初からそんな話ししかしていませんが・・・
>だから何故分からないのかと不思議に思っていました。
>問題を提示して、その解決法を書いているにも関わらず、解決すること自体が矛盾しているとか意味不明な事を言われて困っております。
...どうも、貴方には並列処理について書く際に
・オブジェクト指向と絡めないと並列処理は成立しない。
・オブジェクト指向の中に変数のアクセス範囲の検討がある。
という (貴方にとっては余りにも当たり前すぎて書かれていない) 前提があるようですね。
その前提を余りにも絶対視するが故に、並列処理だけでなくオブジェクト指向的にもダメなサンプルを「並列処理が動かない例」として出しても平気という処でしょうか。
しかしながら、ここは並列処理に言及しているエントリなので、並列処理以外にも原因があるケースを想定して問題を見る読者はほぼいないでしょう。
たとえ並列処理がオブジェクト指向の上に成り立っているとしても、です。
今回のケースなら、問題解決後も変数のアクセス範囲が変わらない事を大半の読者は想定します。
それが変わってしまう答えがいきなり提示されるので、あるまじろさんのような疑問を持つ人が出てくるのです。
蛇足ながら私も最初はあるまじろさんと同じ疑問を持っていました。
並列処理で問題を起こすサンプルを提示するなら、オブジェクト指向的には正しいが、並列処理をすると問題を起こすサンプルにして欲しいです。
もしオブジェクト指向的にも間違っている例を使わざるを得ないなら、その際は答えを同列に扱って欲くないですね。
「並列処理だけで考えればロック掛けるしかないけど、もし flag が外部から変更される必要がないなら flag をローカル変数にして外部からアクセスできなくするのが本筋」
とか、書きようは幾らでもあると思いますので。
>※あるまじろさんはいつもこんな調子です。何時も一部の文を切り抜いて曲解します。
>ですからこちらとしては、荒らしか本当に文章が読めないのかのうちどちらかしかないと考えております。
別に曲解してるのでも、荒らしでも、文章が読めないのでもなく、多分あるまじろさんが文章を読んだ時の前提が、貴方が読者に求めている前提と違うだけでしょう。
前提が違う解釈なので曲解に見えてしまうのでしょうが、基本ただの説明不足です。
...曲解っていうのはね、例えば「中の人の徒然草329」を読んで
「会話が不可能だとか、国語を学ぶ事を勧めるとか書いた直後にこんな事 (読解力の部分) 書いたエントリ挙げやがって、俺 (Geo=TK3) へのあてつけだな!」
と私が怒り出すケースの事を言うんですよ :p 。
>私が言っているのは、初めに変数の範囲をよく考えて、それでも駄目ならばロックしかないと言う事です。
ここには同意します。
> >正しくロックをかけた場合、動作するのに決まっています。
> >そうでないならば、問題解決法として提示しません。
>
> ...つまり私が理解できなかった下記の文は
>
> >大概flagの様なステータス系変数が外部からアクセスされる時は、並列処理は動作しません。
> ↓
> >大概flagの様なステータス系変数が外部からアクセスされる時は、“ロックを掛けないと”並列処理は動作しません。
>
> と言う解釈でよいという事ですね。
> それぞれの解決策がどういうケースを想定しているかを明言した直後に、何の前置きもなく解決策を講じていないケースに言及すると思ってなかったので、意味が理解できませんでした。
>
>
> >> オブジェクト指向的に正しくないといけない、とか、変数のアクセス範囲を狭めればいい とか、そんな次元の話は始めからしていないんですよ。
> >最初からそんな話ししかしていませんが・・・
> >だから何故分からないのかと不思議に思っていました。
> >問題を提示して、その解決法を書いているにも関わらず、解決すること自体が矛盾しているとか意味不明な事を言われて困っております。
>
> ...どうも、貴方には並列処理について書く際に
>
> ・オブジェクト指向と絡めないと並列処理は成立しない。
> ・オブジェクト指向の中に変数のアクセス範囲の検討がある。
>
> という (貴方にとっては余りにも当たり前すぎて書かれていない) 前提があるようですね。
> その前提を余りにも絶対視するが故に、並列処理だけでなくオブジェクト指向的にもダメなサンプルを「並列処理が動かない例」として出しても平気という処でしょうか。
>
「さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。」
とちゃんと書いております。
どちらが望ましいのかと書いているのですから、「flagをローカル変数にする」か「ロックを掛ける」であり、両方が解決法としてふさわしいわけです。
どちらか一方を書くと、「並列処理って、ロックを書けなくてもローカル変数にすれば大丈夫なんだな。あれ?でもローカル変数に出来ないや・・・ならば並列処理は無理かな。」と読者に誤解される恐れがあります。
ローカル変数しか書いていない場合は、「ローカル変数に出来なければ並列処理は出来ない」事になってしまいます。
またロックしか言わない場合、デッドロックなどのバグを生む恐れがありますので、読者を危ない方向へ導く事になります。
落ち着いてちゃんと読んでほしいな。
文章は全ての文に意味があり、その並びも設計されて書かれているのですから、ちゃんと一文一文を読まないと文章は理解できません。
私にとって文章もまたプログラミングです。
分析・設計・実装の手順で書いております。
> しかしながら、ここは並列処理に言及しているエントリなので、並列処理以外にも原因があるケースを想定して問題を見る読者はほぼいないでしょう。
> たとえ並列処理がオブジェクト指向の上に成り立っているとしても、です。
>
> 今回のケースなら、問題解決後も変数のアクセス範囲が変わらない事を大半の読者は想定します。
> それが変わってしまう答えがいきなり提示されるので、あるまじろさんのような疑問を持つ人が出てくるのです。
> 蛇足ながら私も最初はあるまじろさんと同じ疑問を持っていました。
>
> 並列処理で問題を起こすサンプルを提示するなら、オブジェクト指向的には正しいが、並列処理をすると問題を起こすサンプルにして欲しいです。
> もしオブジェクト指向的にも間違っている例を使わざるを得ないなら、その際は答えを同列に扱って欲くないですね。
情報処理技術はつながっているから学習するべきだというテーマも書いております。
それに、スレッドセーフの定義が「並列的に処理しても仕様通り動く事」(極力簡潔にしています)ですから、シングルスレッドでも「なんだかなー」のプログラムは、並列処理でもやはり駄目なわけです。
オブジェクト指向言語で実装する時、ちゃんとオブジェクト指向しないと問題外です。
これは非常に重要な事であり、書かないわけにはいきません。
ちなみに、関数型言語で並列処理する場合も、「設計が駄目ならば並列処理も駄目」です。
シングルスレッドでも問題があるプログラムは並列処理をしても問題です。
>「さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
>その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
>このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。」
>とちゃんと書いております。
その文章があるからこそ
・オブジェクト指向と絡めないと並列処理は成立しない。
・オブジェクト指向の中に変数のアクセス範囲の検討がある。
という書かれていない前提があり、更に読者も同じ前提を持っているとするほどに絶対視しているから
・オブジェクト指向的にもダメなサンプルを並列処理が動かない例として出しても平気
なのでは?と思っています。
そもそもその両者が解決法としてふさわしくなるのは flag変数のアクセス範囲が広いからです。
しかし前者の解決法「flagをローカル変数にする」=「変数のアクセス範囲を検討する」は、並列処理に特有の解決法ではありません。
本文中にも
>ですが、オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。
とあるように「flagをローカル変数にする」事はオブジェクト指向的な解決法であり、つまり並列処理とは関係なく検討すべき内容です。
それはすなわちオブジェクト指向的に正しいプログラムにおいて「flagをローカル変数にする」という解決法は有り得ないという事を意味します。
オブジェクト指向的に正しいプログラムであれば必ず並列処理は動作するというなら別ですが、現実にはそうでない以上、並列処理に特有といえる解決方法はロックしか有りません。
にも関わらずロックについての説明がほとんどなく、変数のアクセス範囲ばかりに言及しているから、前述のような前提などがあるのではないか?と思わざるを得ないのです。
解決策としてロックしか提示しなかった場合にデッドロックなどのバグを発生させる危ない方向に誘導する危険性を懸念されていますが、むしろそういう点にまできちんと触れておく方が並列処理のエントリとしてはよかったのではないでしょうか。
# その点に関しては私も過去のコメントで言及しておくべきでした。
# 謹んで謝罪いたします。
>落ち着いてちゃんと読んでほしいな。
>文章は全ての文に意味があり、その並びも設計されて書かれているのですから、ちゃんと一文一文を読まないと文章は理解できません。
すみません、どうにか理解しようとして連休一日潰して何度も読み返しましたが、結局ムリでした。
やっぱり前提条件も明記しないままに複数の解釈が成立する文章を何度読み返した処で、何が言いたいのかなんて理解出来ません。
だからコメント欄で、もしかしてこういう前提条件をもっているのか?とか、どういう意図で書いた文章なの?とか聞いてるんですよ。
まぁそれだけでなくて異議なり意見なり要望なりも書いてますが。
>情報処理技術はつながっているから学習するべきだというテーマも書いております。
>それに、スレッドセーフの定義が「並列的に処理しても仕様通り動く事」(極力簡潔にしています)ですから、シングルスレッドでも「なんだかなー」のプログラムは、並列処理でもやはり駄目なわけです。
>オブジェクト指向言語で実装する時、ちゃんとオブジェクト指向しないと問題外です。
>これは非常に重要な事であり、書かないわけにはいきません。
>ちなみに、関数型言語で並列処理する場合も、「設計が駄目ならば並列処理も駄目」です。
>シングルスレッドでも問題があるプログラムは並列処理をしても問題です。
つながっているから学習するべき、はいいんですが、だからといってオブジェクト指向と並列処理をまとめて扱わなければならない事にはなりません。
また並列処理には並列処理であるが故に気をつけなければならない事がある筈で、並列処理メインのエントリなら、オブジェクト指向で重要な事よりも並列処理特有の事情の方がよっぽど「書かない訳にはいかない」事でしょ。
更に (スレッドセーフの定義の是非などはおいておくとして) シングルスレッドで問題があるプログラムが並列処理でもダメなのは当たり前の話です。
そんなプログラムを何の前置きもなく「並列処理で問題の起こるコード」として提示する事自体どうかと思いますが、挙句にシングルスレッドで問題なく動くようにするだけの事を「並列処理を動作させる為の解決法」とするのは愚の骨頂でしょう。
サンプルで妥当な解決策に見えるのは、複数スレッド間でデータのやり取りがない仕様を想定した為にシングルスレッドで正しく動くようにすればよかっただけの話に過ぎませんよ。
繰り返しになりますが並列処理のエントリなら「シングルスレッドでは問題のないプログラムが、並列処理では『なんだかなー』になってしまう例」をサンプルとして提示すべきだし、そうできないなら「並列処理に絡む部分だけを問題にすべき」です。
なんというか、無理やり感がただよっていますね。
余りにも苦しいコメントです。
自分が読み間違った事を認めてはいかがでしょうか?
例えば、
>その文章があるからこそ
>・オブジェクト指向と絡めないと並列処理は成立しない。
>・オブジェクト指向の中に変数のアクセス範囲の検討がある。
>という書かれていない前提があり、更に読者も同じ前提を持っているとするほどに絶対視して
>いるから
>・オブジェクト指向的にもダメなサンプルを並列処理が動かない例として出しても平気
>なのでは?と思っています。
これ自体が凄い無理やりです。
何度も言っているように、並列処理単体で考えるなんて事あり得ません。
オブジェクト指向言語でプログラミングをして、「並列処理をしたいんだからオブジェクト指向は無視したぜ」なんて言い訳は通用しません。
それと、私が書いている文章をちゃんと読んでいないと指摘しています。
前提ではなくて【書いているのです】
それが本当に分からないのであれば、読解力がなさすぎます。
この記事の最後の方に、情報処理技術はつながっていると明記しております。
こういったところが、無理やり難癖をつけているか、本当に読解能力がないのかしか考えられないゆえんです。
しかもあなたは、
>しかし前者の解決法「flagをローカル変数にする」=「変数のアクセス範囲を検討する」は、
>並列処理に特有の解決法ではありません。
と書いておりますよね。
従って、どちらかというと難癖ですね。
自身でも変数を考えるのは当たり前だと明言しておきながら、並列処理と同時に考えられないといのは矛盾しております。
さらに貴方は私の記事を無視して
>それはすなわちオブジェクト指向的に正しいプログラムにおいて「flagをローカル変数にする」という解決法は有り得ないという事を意味します。
と話しを勝手に進めていますね。
だから、何度も言いますが、私はオブジェクト指向と並列処理の接点を書いているのです。
その接点を書くのが目的なのに、そういった事を書くはずがありません。
難癖をつけていると感じましたが、どうやら貴方の場合は両方なようですね。
読解能力がないうえに難癖をつけてくる。非常に迷惑です。
あと、
「
つながっているから学習するべき、はいいんですが、だからといってオブジェクト指向と並列処理をまとめて扱わなければならない事にはなりません。
また並列処理には並列処理であるが故に気をつけなければならない事がある筈で、並列処理メインのエントリなら、オブジェクト指向で重要な事よりも並列処理特有の事情の方がよっぽど「書かない訳にはいかない」事でしょ。
更に (スレッドセーフの定義の是非などはおいておくとして) シングルスレッドで問題があるプログラムが並列処理でもダメなのは当たり前の話です。
そんなプログラムを何の前置きもなく「並列処理で問題の起こるコード」として提示する事自体どうかと思いますが、挙句にシングルスレッドで問題なく動くようにするだけの事を「並列処理を動作させる為の解決法」とするのは愚の骨頂でしょう。
サンプルで妥当な解決策に見えるのは、複数スレッド間でデータのやり取りがない仕様を想定した為にシングルスレッドで正しく動くようにすればよかっただけの話に過ぎませんよ。
繰り返しになりますが並列処理のエントリなら「シングルスレッドでは問題のないプログラムが、並列処理では『なんだかなー』になってしまう例」をサンプルとして提示すべきだし、そうできないなら「並列処理に絡む部分だけを問題にすべき」です。
」
これらは貴方の意見を押し付けているだけです。
私は並列処理を学習する前にオブジェクト指向を学習するべきだと考えております。
貴方が並列処理だけを学習すればいいと考えているのであれば、貴方自身が自分のブログに書けばいいだけの話しです。
貴方は自分の意見と、私が書こうとしている記事の内容を混同しております。
何度も言っておりますが、スレッドセーフの定義から考えて、オブジェクト指向として正しい事は前提です。
その前提を経ずに並列処理だけ考えても問題外なのです。
逐次処理でも問題があるものは、並列処理でも問題があるのです。
それは並列処理の基礎中の基礎であり書く必要があります。
スレッドセーフの定義を満たしていないものは問題です。
そして、スレッドセーフでないプログラムは並列処理で正常に動作しません。
その基礎すらも書いていない方が問題かと思います。
それに加えて、この部分でも文章を読めていませんね・・・
総論しますと、貴方は自分の意見だけで物事を捉え、人の記事の内容を読もうともせず、自分が考える内容と違うと難癖をつけているだけです。
※おまけに読解力に問題があるようです
貴方が並列処理について書きたいのであれば、自分のブログですればいいのです。
人のブログに来て、自分の意見と違うからと言って難癖を書くのは非常に迷惑な行為です。
自分が知りもしない事で難癖をつけて、おまけに一人で言えないから、他の人を煽って集団でわめき散らかす人よりもましですが、十分迷惑な行為なので止めてください。
悪い事はいいません。
貴方の場合、専門書をもっと読んで読解力を身につける所から始めるべきです。
>そんなプログラムを何の前置きもなく「並列処理で問題の起こるコード」として提示する事自体どうかと思いますが、挙句にシングルスレッドで問題なく動くようにするだけの事を「並列処理を動作させる為の解決法」とするのは愚の骨頂でしょう。
あと、どうやら貴方は根本的に理解されていないようですが、このコードは「並列的にも問題があるもの」です。
基礎中の基礎で躓いているのが感じ取れます。
貴方が並列処理に関して知らない事はよくわかりました。
知らない事を無理やりコメントするのはよした方がよろしいかと思います。
知らない事を無理に書こうとするから難癖にしかならないのでしょう。
どうやら、知らないのにもかかわらず、無理やり文章を曲解して難癖をつける事がはやっているようですが、そんな恥ずかしい事は止めておいた方が貴方の為です。
恥ずかしい流行りを真似しても何の意味もありません。
貴方が恥ずかしくなるだけです。
>というか、未定義ではなくて、コンパイルエラーが出るよ。
「未定義」になり「コンパイルエラー」が出るね。
で、この場合の解決策は?
> >というか、未定義ではなくて、コンパイルエラーが出るよ。
>
> 「未定義」になり「コンパイルエラー」が出るね。
>
> で、この場合の解決策は?
未定義ではなくて、アクセスするコードから見えなくなるからコンパイルエラーです。
リファクタリングを知らないのですね・・・
だから、知りもしないのに、無理やり間違っていると言おうとするから、難癖にしかならないと言っているのですが・・・
何を言っても無駄そうですからこれからコメントを拒否します。
>何を言っても無駄そうですからこれからコメントを拒否します
それは答えられないからコメントを拒否すると言うことですね。
原因は何であれ、コンパイルエラーは出る。
ただ、その時の解決方法が解らないんだよね。
これは凄い。余りにも酷いので掲載する事にしました。
アクセス範囲を変えて、エラーが出たら対処できないとは!
どうやらプログラミングを全く知らないのですね・・・
おまけに私のコメントも読んでいないようですね。
日本語の読解力を高めるための読書と、プログラミングの基礎から学ぶ事をお勧めします。
今ふと思ったのですが、あるまじろ氏はプログラミングを全く知らないようなので、もしかして私の質問したかったのかな?
そうだとしたら質問の仕方も考えた方がいいです。
人に質問する時は、間違っているとか矛盾しているとか言ったら駄目です。
分からないからその人に聞くのであって、
教えてもらうからにはマナーをわきまえる必要があります。
そもそも、自分が分からないのは他人のせいだと考えたら駄目です。
ひとまず質問の仕方を職場の先輩に教えてもらおう。
>アクセス範囲を変えて、エラーが出たら対処できないとは!
これだけの条件じゃ自分には対応できないね。
外部参照していた flag が見えなくなるわけだから。
どうせ回答も出来ないのだろうけど。
変に回答するとボロがでるしね。
誰もが見て納得できる回答を示すことができる?
>ただ、その時の解決方法が解らないんだよね。
これはインドリさんに対する問いかけだったんだけどな。
まあ、自分でも判らんから教えてくださいよ。
> >アクセス範囲を変えて、エラーが出たら対処できないとは!
>
> これだけの条件じゃ自分には対応できないね。
> 外部参照していた flag が見えなくなるわけだから。
>
> どうせ回答も出来ないのだろうけど。
> 変に回答するとボロがでるしね。
>
> 誰もが見て納得できる回答を示すことができる?
>
> >ただ、その時の解決方法が解らないんだよね。
>
> これはインドリさんに対する問いかけだったんだけどな。
>
> まあ、自分でも判らんから教えてくださいよ。
知りもしないのに、言っているという事がよくわかりますね。
どうしてそんな恥ずかしい事が出来るのかと不思議でなりません。
それを知らないのは貴方ぐらいのものです。
リファクタリングを知らなくても分かる、基本的なプログラミングです。
誰でも知っていると思いますが、教えて欲しいようだから一応書きます。
・当然のことながらヴァージョン管理ソフトに今のコードをコミットする。
・グローバル変数を取り除く。
・ローカル変数にする。
・エラー箇所を吟味する。
・その変数の必要がないように、オブジェクト指向設計を変える。
もしくは
・変数を変更するメソッドまたはプロパティを用意してロックを掛ける。
プログラミングの基礎も知らずに、人に挑戦的な事を書くのはよした方がよいですよ。
その態度じゃ、普通教えてもらえません。
それにしても、E氏と似ているな・・・
自分の過ちを認められずにまた難癖をつけてくるだろうから先に言っておきます。
当然のことながら「ソースコードを変える権限がない時は対処のしようがありません」
変更できないのですから、デバッグもままなりません。
デバッグが出来ないのであれば、当然エラーも修正できません。
これが分からないのであれば、貴方にかまっている暇はないので無視します。
実際問題、「日本語が読めない」「プログラミングの基礎も知らない」「過ちを認めない」
の三拍子をされたら会話自体が不可能ですし、そんな態度の人に教える義理もありませんしね。
私はテクニカルアドバイザーもしているので、商売として情報を提供している身です。
それを、こんな変な人にただでサービスを提供する必要はありません。
おっと、忘れていた。
相変わらず人の話しを聞いていないようなのでもう一度言います。
プログラミングの基礎も知らないようですから、恐らく若い人なのでしょう。
「人にものを教えてもらう態度を先輩に教えてもらいましょう」
貴方の場合、コメントする以前の問題ですから、先輩に社会人としての基礎を教えてもらってから来てください。
> 「さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
> その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
> このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。」
> とちゃんと書いております。
> どちらが望ましいのかと書いているのですから、「flagをローカル変数にする」か「ロックを掛ける」であり、両方が解決法としてふさわしいわけです。
元のプログラムには、「flag = true; //※flag変数は外部から変えられると仮定する」と前提がなされています。「flagをローカル変数にする」と、外部から変えることができなくなるため、前提が崩れてしまいます。普通は、この前提を覆さずに、問題を解決します。前提を覆さなければ解決できない場合は、覆す理由を説明します。
もし、「うるさく「変数を外部に出すな」とカプセル化の原則を言われます。」というのが、前提を覆すことの説明であるなら、言葉が足りなすぎます。この場合、組むところまでいってしまったプログラムを、設計からやり直さなければなりません。カプセル化の原則は「問題を起こさないための方法」であって、「問題を解決するための方法」ではありません。もっとも普通は、原則があって、原則を破るから「外部から変えられると仮定する」と、断りを入れるのですけどね。
たくさんの本を読んでいると公言するわりに、説明の仕方は下手ですね。もっと、「どの様に文が構成されているか」ということにも気をつけて、本を読んでください。
「自分が知っていることは他人も知っていると思っている」という自覚があるなら、「自分は知っているこのことは、他人も知っているだろうか」と自問するクセを付けて下さい。「私ごときが知っているのだから」というのは、「私でさえ知っていることも知らないのか」という侮りでもあります。
これまでも何度も、「読み返せ」という指摘をされているはずです。「何も知らない人が読んで理解できるだろうか」という視点(初心者への説明であるならそういう視点が必要なはずです)で、読み返してから投稿して下さい。また、アドバイスを仕事にしているからこういう場では仕事に関わるようなことは書けないというのなら、一切書かないでください。つまり、ブログから撤退してください。中途半端な情報があることは、大変迷惑です。
貴方も相変わらず、人の話しを聞きませんね。
ちゃんと問題があると説明しております。
引用
「
このプログラムでも、false時の処理がされる場合があります。逐次処理に慣れきった人は、ここで足元をすくわれます。
ですが、複数の処理を並列的に行っているのですから、flagを変える処理が割り込めば、falseになる可能性があるのです。
こんな単純な処理ですら、逐次処理の感覚でしていれば罠にはまります。
」
問題のあるプログラムを提示した直後に書いてあるので、普通は気付きます。
貴方も文章を読まず、会話にずれが生じている事が多々ありますが、
(@ITの掲示板やコラムのコメント欄を参照)
あわてずにちゃんと人の話しを聞きましょう。
不自然なコメントは、何かを言ってやろうと無理やり言っているように聞こえます。
かなり印象が悪いので、冷静に人の話しを聞くべきです。
あと、知らない用語が書いていたら相手が可笑しいと考えて、「プロじゃない」などといった事がありましたよね。
自分が知らない事は間違っているという考えは止めた方がいいですよ。
そんなことではチームプレーはできません。
また曲解されたら嫌なので明言しておきますが、私は攻撃ではなくて忠告をしております。
人の忠告は素直に聞いた方がいいですよ。
最後に貴方は根本的な勘違いをしております。
私がこの人たちに注意をしているのは「人にものを尋ねる時の態度」です。
貴方は聞く側は何をしてもいいという持論を持っているようですが、世間一般では通用しません。
会話は両者が礼儀をわきまえてするものです。
特にここは公共の場です。
人様に失礼がないようにしましょう。
この問題のプログラム、注釈を書かないとローカル変数にも見えます。
だからこれはグローバル変数であり、外部からアクセスされていると一々書いているのです。
恐らく難癖を如何にしてつけようか考えているから、この様な普通の事も気付かないのだと思いますが、それでは自分は日本語が読めないと宣伝しているのと同じです。
何故、こんな恥ずかしい事が出来るのか到底分りませんが、もういい加減に自分の能力のなさをアピールして、人様に迷惑をかけるのはよしましょう。
> 貴方も相変わらず、人の話しを聞きませんね。
> ちゃんと問題があると説明しております。
>
> 引用
> 「
> このプログラムでも、false時の処理がされる場合があります。逐次処理に慣れきった人は、ここで足元をすくわれます。
> ですが、複数の処理を並列的に行っているのですから、flagを変える処理が割り込めば、falseになる可能性があるのです。
> こんな単純な処理ですら、逐次処理の感覚でしていれば罠にはまります。
> 」
>
> 問題のあるプログラムを提示した直後に書いてあるので、普通は気付きます。
指摘と、ずれていますね。ちゃんと読んでください。
結論に至る理由:
インドリさんが提示されたコードは、次の通りです。
flag = true; //※flag変数は外部から変えられると仮定する
if ( flag == true ) {
//ここに来るよね?
} else {
//ここに来る事はないはずだけど・・・
}
これに対して、修正の方法としてあげてあるのが、次の通りです。
> さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
> その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
> このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。
> それ故、スレッドローカルストレージが多用されているわけです。
> この答えはなれない人にとっては難しく感じるかもしれません。
> ですが、オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。
ここに書いてあるのは、「(外部からアクセスできる)flagをローカル変数にする(ことで、外部からアクセスできなくする)」と、「ロックを掛ける」ということです。ここで、あるまじろさんから、「ローカル変数にするということは、最初の仮定が成り立たなくなるよ。」と、指摘があるわけです。最初に「外部からアクセスできる」という前提が与えられています。ローカル変数にするとアクセスできなくなるので、外部で flag を扱っている箇所でコンパイルエラーが発生します。これを直さないといけません。
ところで、flag は外部からアクセスできたわけですが、なぜ、アクセス出来るようにしてあったのでしょう?
すくなくとも、本文にその理由は書かれていません。ですから、「アクセスしなければ仕様を満たせない」という前提で、説明を読み進めます、普通は。しかし、インドリさんが用意された答えは「アクセスできなくする」でした。つまり、「アクセスしなくても仕様は満たせた」ということであり、外部からアクセスできるのは「バグ」であったということになります。
そんなアホな。
もちろん、インドリさんもコメントで「だから、設計を見直せと言っているわけです。」と書かれていますが、本文からはそれを見つけることは出来ませんでした。しかし、もしかしたら、「オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。」の箇所が、「設計を見直せ」という事だったのかもしれません。しかし、このコードで外部からアクセスできたのは「バグ」だったのです。元々まずい設計を見なすことで、インスタンス共有問題が解決するとは思えません。つまり、説明の方法が悪い、ということです。
また、「カプセル化の原則」は「問題を起こしにくくするための原則」であり、「発生した問題を解決する方法」ではありません。つまり、ここでカプセル化を持ち出すのは誤っています。
結論:
1.本文の内容ではわかりにくい。
2.コメントで補足しなければならないような物を書くな。
3.意味のないコードを例として出すな。
つまり、「説明文として、0点」というわけです。
もちろん、「個人のブログなんだから、そんなに厳密なこというな」というのも、ありです。しかし、それならば、「こうしたらわかりやすい」と指摘していただいているのですから、素直に聞きましょう。あるいは、「これは個人の覚え書きです」と付記し、かつ、誰かに読ませるような書き方は止めましょう。
さて、「スレッド ローカル ストレージ」という言葉が出ていますが、それであれば、“ローカル変数にする必要はない”かもしれません。このコードの断片が書かれているメソッドの呼び出し元が、flag を供給する様に修正しても、つまり引数として渡すようにしても、スレッド セーフになるかもしれません。全体的な仕様として正しい振る舞いをするかどうかは、わかりませんが。また、ローカル変数にしても、それが複数のスレッドで共有されるような宣言の仕方をしていると、スレッド セーフでは無くなります。1990年代に SUN が用意していた C 標準ライブラリでは、strtok 関数がローカルな静的領域を使っていたためにスレッド クリティカルでした。コンテナであるなら、蓄えるデータは複数のスレッドから共有されなければならないため、外部から直接アクセスできないようにしていても、ここで言われているような問題は発生します。すなわち、STL のコンテナ クラスでは、実際に発生する問題です。また、OpenMP では、ローカル変数をスレッドに共有させることが出来ますから、書き方によっては、単にローカル変数にするだけでは問題は収まりません。しかし、本文には単に「ローカル変数にする」としか書かれておらず、詳細はわかりません。
結局、ごく限られた環境をターゲットとしているにもかかわらず、そのターゲットが、まったくわかりません。もっと「説明をする」とはどういうことか調べ、文書を設計をしてから書いてください。
ああ、それと、
> では、どうすればいいのかと言いますと、純粋に知識と経験から判断するしかありません。
これは、「そんなことはない」と申しておきます。きちんと設計してください。分析してください。判断するのに、知識はいるかもしれませんが、経験は必要ありません。マルチスレッドについてはまったく知識も経験もなかった私でしたが、設計、分析、机上デバッグで、問題を未然に防ぐことが出来ました。
それから、この「他からアクセスされるかもしれない」という問題は、マルチスレッドだから発生するわけではありません。逐次処理でも発生します。そんなことはご存知かもしれませんが、これまでの記事全てでご存知では無いような書き方がされているので、気になりました。
もうひとつ。聞いている、質問しているわけではありません。詰問しています。もう一度書いておきますが、デタラメをデタラメなまま放置し、デタラメを「正しい」と言い張るようなことはやめてください。少なくとも、CodeZine のデタラメ記事は、修正してください。
もう一個。確かに、読み違えたこと、読み違えさせたことは、何度かあります。しかし。同じ人とひとつの話題の中で何度も読み違いが発生したこと、合意に至らなかったことは、インドリさんの他にはObjectさんしかいません。そのことを考えると、インドリさんとObjectさんが特殊だと判断する方が妥当と考えます。まぁ、マイノリティがダメとはいいませんが。しかし、他の人との衝突が多いインドリさんやObjectさんがマジョリティになったら、コミュニケーションできない人だらけになってしまうように思われます。それは、怖い。
> > 貴方も相変わらず、人の話しを聞きませんね。
> > ちゃんと問題があると説明しております。
> >
> > 引用
> > 「
> > このプログラムでも、false時の処理がされる場合があります。逐次処理に慣れきった人は、ここで足元をすくわれます。
> > ですが、複数の処理を並列的に行っているのですから、flagを変える処理が割り込めば、falseになる可能性があるのです。
> > こんな単純な処理ですら、逐次処理の感覚でしていれば罠にはまります。
> > 」
> >
> > 問題のあるプログラムを提示した直後に書いてあるので、普通は気付きます。
>
> 指摘と、ずれていますね。ちゃんと読んでください。
>
> 結論に至る理由:
> インドリさんが提示されたコードは、次の通りです。
>
> flag = true; //※flag変数は外部から変えられると仮定する
> if ( flag == true ) {
> //ここに来るよね?
> } else {
> //ここに来る事はないはずだけど・・・
> }
>
> これに対して、修正の方法としてあげてあるのが、次の通りです。
>
> > さて、先ほどのプログラムの問題を解決するにはどうすればいいと思いますか?
> > その答えは、「flagをローカル変数にする」か「ロックを掛ける」です。
> > このうちどちらが望ましいかといいますと、ロックはパフォーマンスを低下させるので、ローカル変数にする方です。
> > それ故、スレッドローカルストレージが多用されているわけです。
> > この答えはなれない人にとっては難しく感じるかもしれません。
> > ですが、オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。
>
> ここに書いてあるのは、「(外部からアクセスできる)flagをローカル変数にする(ことで、外部からアクセスできなくする)」と、「ロックを掛ける」ということです。ここで、あるまじろさんから、「ローカル変数にするということは、最初の仮定が成り立たなくなるよ。」と、指摘があるわけです。最初に「外部からアクセスできる」という前提が与えられています。ローカル変数にするとアクセスできなくなるので、外部で flag を扱っている箇所でコンパイルエラーが発生します。これを直さないといけません。
>
本当に読解能力がありませんね。
> ところで、flag は外部からアクセスできたわけですが、なぜ、アクセス出来るようにしてあったのでしょう?
>
> すくなくとも、本文にその理由は書かれていません。ですから、「アクセスしなければ仕様を満たせない」という前提で、説明を読み進めます、普通は。しかし、インドリさんが用意された答えは「アクセスできなくする」でした。つまり、「アクセスしなくても仕様は満たせた」ということであり、外部からアクセスできるのは「バグ」であったということになります。
>
> そんなアホな。
>
> もちろん、インドリさんもコメントで「だから、設計を見直せと言っているわけです。」と書かれていますが、本文からはそれを見つけることは出来ませんでした。しかし、もしかしたら、「オブジェクト指向では、口うるさく「変数を外部に出すな」とカプセル化の原則を言われます。」の箇所が、「設計を見直せ」という事だったのかもしれません。しかし、このコードで外部からアクセスできたのは「バグ」だったのです。元々まずい設計を見なすことで、インスタンス共有問題が解決するとは思えません。つまり、説明の方法が悪い、ということです。
余りにも無理やりすぎて失笑しました。
> また、「カプセル化の原則」は「問題を起こしにくくするための原則」であり、「発生した問題を解決する方法」ではありません。つまり、ここでカプセル化を持ち出すのは誤っています。
>
読解力なさすぎ。
並列処理を知らないまでも、カプセル化の原則を守っていればこんな設計ミスしません。
> 結論:
> 1.本文の内容ではわかりにくい。
> 2.コメントで補足しなければならないような物を書くな。
> 3.意味のないコードを例として出すな。
>
> つまり、「説明文として、0点」というわけです。
> もちろん、「個人のブログなんだから、そんなに厳密なこというな」というのも、ありです。しかし、それならば、「こうしたらわかりやすい」と指摘していただいているのですから、素直に聞きましょう。あるいは、「これは個人の覚え書きです」と付記し、かつ、誰かに読ませるような書き方は止めましょう。
>
貴方の読解能力0点。
>
> さて、「スレッド ローカル ストレージ」という言葉が出ていますが、それであれば、“ローカル変数にする必要はない”かもしれません。このコードの断片が書かれているメソッドの呼び出し元が、flag を供給する様に修正しても、つまり引数として渡すようにしても、スレッド セーフになるかもしれません。全体的な仕様として正しい振る舞いをするかどうかは、わかりませんが。また、ローカル変数にしても、それが複数のスレッドで共有されるような宣言の仕方をしていると、スレッド セーフでは無くなります。1990年代に SUN が用意していた C 標準ライブラリでは、strtok 関数がローカルな静的領域を使っていたためにスレッド クリティカルでした。コンテナであるなら、蓄えるデータは複数のスレッドから共有されなければならないため、外部から直接アクセスできないようにしていても、ここで言われているような問題は発生します。すなわち、STL のコンテナ クラスでは、実際に発生する問題です。また、OpenMP では、ローカル変数をスレッドに共有させることが出来ますから、書き方によっては、単にローカル変数にするだけでは問題は収まりません。しかし、本文には単に「ローカル変数にする」としか書かれておらず、詳細はわかりません。
> 結局、ごく限られた環境をターゲットとしているにもかかわらず、そのターゲットが、まったくわかりません。もっと「説明をする」とはどういうことか調べ、文書を設計をしてから書いてください。
>
だから知識もないのに言うなと言われるのです。
これは並列処理の一番基本的問題です。
それを知らないとしか思えない。
> ああ、それと、
>
> > では、どうすればいいのかと言いますと、純粋に知識と経験から判断するしかありません。
>
> これは、「そんなことはない」と申しておきます。きちんと設計してください。分析してください。判断するのに、知識はいるかもしれませんが、経験は必要ありません。マルチスレッドについてはまったく知識も経験もなかった私でしたが、設計、分析、机上デバッグで、問題を未然に防ぐことが出来ました。
> それから、この「他からアクセスされるかもしれない」という問題は、マルチスレッドだから発生するわけではありません。逐次処理でも発生します。そんなことはご存知かもしれませんが、これまでの記事全てでご存知では無いような書き方がされているので、気になりました。
>
恐ろしく読解能力ありませんね・・・
このコードの断片を数十万行以上から見つけろと言っているのです。
だから経験が必要になります。
また、分析と設計をするに経験が必要ない?
貴方は本当に実務経験ありますか?
> もうひとつ。聞いている、質問しているわけではありません。詰問しています。もう一度書いておきますが、デタラメをデタラメなまま放置し、デタラメを「正しい」と言い張るようなことはやめてください。少なくとも、CodeZine のデタラメ記事は、修正してください。
>
だから氏らいないものをするなと言っています。
あれをでたらめと思っているのは貴方に知識がないからです。
貴方のコメントから並列処理に関して無知だという事が分かりますが、
自分が知らない事を批判をするなと言っているのが分からないようですね・・・
もしかして、並列処理を知らずに、短いサンプルばかり持ち出して問題あると叫んでいる人の言う事を真に受けているのですか?
> もう一個。確かに、読み違えたこと、読み違えさせたことは、何度かあります。しかし。同じ人とひとつの話題の中で何度も読み違いが発生したこと、合意に至らなかったことは、インドリさんの他にはObjectさんしかいません。そのことを考えると、インドリさんとObjectさんが特殊だと判断する方が妥当と考えます。まぁ、マイノリティがダメとはいいませんが。しかし、他の人との衝突が多いインドリさんやObjectさんがマジョリティになったら、コミュニケーションできない人だらけになってしまうように思われます。それは、怖い。
では、今究極に誤読しているのはどう説明するのですか?
並列処理を知らないのにもかかわらず、曲解を繰り返しています。
並列処理を知らずに、おまけに記事を読めずに、指摘をしていると言ってくるとは・・・
この集団はいつもの事ですが、指摘をするという事は、普通その対象を知っていてするものです。
Sleep命令の仕様を知らずに集団でわめいたり、並列処理を知らないのに短いサンプルを動かして、それをもとに集団でわめいたりと、知らない事で指摘しているつもりだというのは余りにも痛いです。
これは技術者に限った話しではありませんが、普通はちゃんと知ってから指摘はするものです。
なおかつ、指摘をする前にちゃんと文章は読むものです。
※素で読めないのかもしれませんが・・・
並列処理の基礎問題を分からないようですが、自分が分からない事を他人のせいにしないでください。
この時するべきことは、礼儀正しく並列処理について聞くか、自分で学習する事です。
余りにも酷くてあきれました。
新人よりも酷い。
新人でもここまで世間知らずではありません。
誤:だから氏らいないものをするなと言っています。
正:だから知らないものを指摘するなと言っています。
もしかして、洗脳されているのかな?
ちゃんと文章を読めば、滅茶苦茶言っているという事が分かるのに、
読解能力のなさと先入観で間違っていると思い込んでいるようですね・・・
でも、普通に考えたら分かると思いますが、間違い云々は知識がないと判別できないものです。
知りもしない事を、誰かの言う事を鵜呑みにして間違っていると騒ぐのは非常に恥ずかしく迷惑な行為です。
技術者たるものちゃんと自分の頭で判断しましょう。
> 本当に読解能力がありませんね。
> 余りにも無理やりすぎて失笑しました
> 読解力なさすぎ。
ええ、無理矢理でしょ。説明が下手すぎて「自然と読めない」から、無理矢理読むしかないのですよ。
> 並列処理を知らないまでも、カプセル化の原則を守っていればこんな設計ミスしません。
だから、全体を通して、なぜ、「外部からアクセスできると仮定する」のか、わからない、と言っているのですが、まだわかりませんか?
カプセル化の原則を守っていないから外部からアクセスできるのであれば、「設計ミス」なんですよ。それは、スレッドクリティカル以前の問題です。スレッドを使わなくても、バグの温床ですよね。だから、原則を知っている人は避けるでしょ。それでも「外部からアクセスできると仮定する」と書いてある。
何のためにこんなこと書いたんです?説明の仕方を設計していないから、読者を混乱させるのですよ。
> これは並列処理の一番基本的問題です。
> それを知らないとしか思えない。
え〜っと、エイプリルフールのジョークですか?その、「一番基本問題」を説明するエントリではないのですか?タイトルには「並列処理で発生する落とし穴を回避せよ」と、書いてありますよ?で、それを説明するには、「説明が下手すぎ」といっているのですけど?
それとも、「ローカル変数にしたからといって問題がなくなるわけではない」とか、「並列処理特有の問題ではない」に対して、「並列処理の一番基本的な問題を知らないとしか思えない」と仰ってます?
インドリさんの場合、コメントが増えると、前に書いてあることと矛盾してくるんですよね。だから余計にわからなくなる。本文は、何を書きたかった(伝えたかった)のか。今、何を書いているのか。ちゃんと把握していますか?
そうそう、CodeZineのコメントで気になったことがあるので、引用しますね。
> インドリ (2010/03/03 09:12):
> >スケジューラーの初期化について
> 並列処理では実行順序が保障されません。
> しかも、アセンブラレベルで命令が実行されております。
> その状態なのですから、初心者がTBBとネイティブスレッド・OpenMPなどの処理を併用させたときに、どのようなプログラムでも正しく実行できると100%の自信を持って言えるでしょうか?私はそんな危険を冒すよりも1行のプログラムを書く方を勧めます。
面白いですよね。「アセンブラレベルで実行されている」と書いてあるのに、「1行のプログラムを書く方を勧めます」と。アセンブラを知っているなら、ソースコードの1行が1アセンブリではない事くらい、知っていますよね。それなのに、1行で書くことを勧めます、と。どうやったら辻褄が合うんでしょう?それとも、アセンブリレベルの「1行」で書けと?まさか、ね。
どうも、理解できないのですよ。「c = 1; d = c;」と1行で書いたら、c と d への代入は他のスレッドから介入されないと仰ってます?それとも、cout に限ってます?まさか、「cout << 1 << 2 << 3;」と書いたら、他のスレッドの介入を受けないと?そんなはず無いですよね。「cout << 1」が basic_ostream<> を返すから、続けて「<< 2」と書けるだけ。つまり「((cout.operator<<(1)).operator<<(2)).operator<<(3);」の、3回のメソッド呼び出しと同義だと、ご存知ですよね?「メソッドの呼び出しが1回だ」なんて、ましてや「1行だから1アセンブリだからスレッドセーフになるはずだ」なんて、仰らないですよね?!
「アセンブラレベルで命令が実行」されると書かれているのに「1行のプログラムを書く方を勧める」と書いているのが矛盾しています。その上で、なぜ1行だと危険ではないのか、説明がなされていません。まったく、説明が下手すぎ。
ん?まさか、初心者が、1つのプログラムの中で、TBB、OpenMP、ネイティブスレッド、pthreadなどを混在させると、どうなるかわからない・・・と仰ってます?いや、それ、誰もそんなこと言ってないし、飛躍しすぎだし。
いやまぁ、それをいうと、この文節がどれにあてたのか、わからないんですよね。「スケジューラーの初期化」と、「1行のプログラムを書く」が、どうにも繋がらないんですよ。いったい、何の関係があるんだろう?
> このコードの断片を数十万行以上から見つけろと言っているのです。
> だから経験が必要になります。
要りませんよ。コードを書く前に設計をしていれば、要りません。だから、初めてのマルチスレッドでも、失敗しなかったと書いていますよ。ああ、「レビューした」とは書いてなかったですね。済みません、レビューして、他の人に確認してもらうことも必要です。ちなみに、その「他の人」も、マルチスレッドは初めての経験でした。つまり、スレッド間でインスタンスを共有することによる危険を認識して、どうやって防ぐかという知識を持ち、適切に設計したので、「並列処理の一番基本的問題」は、未経験なのですよ。
もっとも、設計の前にコードを書いたら、確かに経験が要りますね。それは認めます。が、そんなことしたら時間がもったいないので、勧められません。
インドリさん、設計したことないんですか?そうか、コードを書いてから、そのコードによって考えに気づくのでしたね。コードが先ですね。聞くだけ野暮でした。失礼しました。
でも、他の人に読んでもらう物を書くときは、ちゃんと設計してくださいね。
そうそう、Objectさんもそうでしたが、「誤解している」というわりに、「どこを、どう、誤解しているか」の説明はないんですね。私はいったい、何を、誤解していると思っているのですか?私には、インドリさんこそ、並列処理の表面的なことだけを知って、知ったかぶりしているように見えるのですが。メモリリークとオーバーフローの件。番兵メソッドの件。StringCchCopyの件。ブロック化の件。値渡しと参照渡しの件。coutの件。とりあえず印象的だったのはこれだけですが、印象的な物だけでも1年ほどの間にこれだけあります。これだけの「間違い」を挽回するには、ちょっと「正しいことの実績」が、足りなくありませんか?
> > 本当に読解能力がありませんね。
> > 余りにも無理やりすぎて失笑しました
> > 読解力なさすぎ。
> ええ、無理矢理でしょ。説明が下手すぎて「自然と読めない」から、無理矢理読むしかないのですよ。
>
貴方の読解能力がなさ過ぎて、日本語を自然に読めないわけですね。
わかります。@ITのコラムにも変なコメントを書いて迷惑かけたりしているからね。
> > 並列処理を知らないまでも、カプセル化の原則を守っていればこんな設計ミスしません。
> だから、全体を通して、なぜ、「外部からアクセスできると仮定する」のか、わからない、と言っているのですが、まだわかりませんか?
> カプセル化の原則を守っていないから外部からアクセスできるのであれば、「設計ミス」なんですよ。それは、スレッドクリティカル以前の問題です。スレッドを使わなくても、バグの温床ですよね。だから、原則を知っている人は避けるでしょ。それでも「外部からアクセスできると仮定する」と書いてある。
> 何のためにこんなこと書いたんです?説明の仕方を設計していないから、読者を混乱させるのですよ。
>
混乱しているのは酷く読解能力がない証拠。
例のプログラムがローカル変数に見えなくもないし、どこからもアクセスされていなければ問題はひとまず生じません。
あのプログラムがローカル変数としたら、問題解決法がローカル変数にするとはおかしな話でしょう。
大丈夫ですか?
> > これは並列処理の一番基本的問題です。
> > それを知らないとしか思えない。
> え〜っと、エイプリルフールのジョークですか?その、「一番基本問題」を説明するエントリではないのですか?タイトルには「並列処理で発生する落とし穴を回避せよ」と、書いてありますよ?で、それを説明するには、「説明が下手すぎ」といっているのですけど?
> それとも、「ローカル変数にしたからといって問題がなくなるわけではない」とか、「並列処理特有の問題ではない」に対して、「並列処理の一番基本的な問題を知らないとしか思えない」と仰ってます?
> インドリさんの場合、コメントが増えると、前に書いてあることと矛盾してくるんですよね。だから余計にわからなくなる。本文は、何を書きたかった(伝えたかった)のか。今、何を書いているのか。ちゃんと把握していますか?
>
やはり、分かっていない。
日本語が通じない人とコメントのやり取りをするのは無理ですね。
貴方が知りもしない事を指摘しているつもりなので、知りもしない事は指摘なぞ出来ないと当たり前のことを言っているのです。
> そうそう、CodeZineのコメントで気になったことがあるので、引用しますね。
> > インドリ (2010/03/03 09:12):
> > >スケジューラーの初期化について
> > 並列処理では実行順序が保障されません。
> > しかも、アセンブラレベルで命令が実行されております。
> > その状態なのですから、初心者がTBBとネイティブスレッド・OpenMPなどの処理を併用させたときに、どのようなプログラムでも正しく実行できると100%の自信を持って言えるでしょうか?私はそんな危険を冒すよりも1行のプログラムを書く方を勧めます。
> 面白いですよね。「アセンブラレベルで実行されている」と書いてあるのに、「1行のプログラムを書く方を勧めます」と。アセンブラを知っているなら、ソースコードの1行が1アセンブリではない事くらい、知っていますよね。それなのに、1行で書くことを勧めます、と。どうやったら辻褄が合うんでしょう?それとも、アセンブリレベルの「1行」で書けと?まさか、ね。
???読解能力がない人が、誤読したまま言っていくるものだから、識別が難しいですね。
極力行数が少ない方がいいとは書いた事がありますが、アセンブラで1行をかく事なんて進めていません。
それに、あれは(よくわからんけど指摘しているつもりの場所を想像してみた)どちらかというとアトミックなコードを指しています。
> どうも、理解できないのですよ。「c = 1; d = c;」と1行で書いたら、c と d への代入は他のスレッドから介入されないと仰ってます?それとも、cout に限ってます?まさか、「cout << 1 << 2 << 3;」と書いたら、他のスレッドの介入を受けないと?そんなはず無いですよね。「cout << 1」が basic_ostream<> を返すから、続けて「<< 2」と書けるだけ。つまり「((cout.operator<<(1)).operator<<(2)).operator<<(3);」の、3回のメソッド呼び出しと同義だと、ご存知ですよね?「メソッドの呼び出しが1回だ」なんて、ましてや「1行だから1アセンブリだからスレッドセーフになるはずだ」なんて、仰らないですよね?!
> 「アセンブラレベルで命令が実行」されると書かれているのに「1行のプログラムを書く方を勧める」と書いているのが矛盾しています。その上で、なぜ1行だと危険ではないのか、説明がなされていません。まったく、説明が下手すぎ。
> ん?まさか、初心者が、1つのプログラムの中で、TBB、OpenMP、ネイティブスレッド、pthreadなどを混在させると、どうなるかわからない・・・と仰ってます?いや、それ、誰もそんなこと言ってないし、飛躍しすぎだし。
> いやまぁ、それをいうと、この文節がどれにあてたのか、わからないんですよね。「スケジューラーの初期化」と、「1行のプログラムを書く」が、どうにも繋がらないんですよ。いったい、何の関係があるんだろう?
>
あのね、だから無知な事を指摘したら駄目だと言っているのです。
coutの様なグローバルなオブジェクトは、並列処理で同時にアクセスしないのは基本です。
短いプログラムを提示して大丈夫だといった痛い人がいますが、並列処理の問題は門司海プログラムでは露呈しません。
痛い人の言う事を鵜呑みにしているから可笑しくなるのです。
このぐらいの事は基礎レベルなので、並列関係の書籍を見たら書いてあるはずだし、グローバル変数を同時にアクセスしてはならないのだから、グローバルなオブジェクトを同時にアクセスしてはならないぐらいの事は分かりませんか?
先入観は怖いですね。
>
> > このコードの断片を数十万行以上から見つけろと言っているのです。
> > だから経験が必要になります。
> 要りませんよ。コードを書く前に設計をしていれば、要りません。だから、初めてのマルチスレッドでも、失敗しなかったと書いていますよ。ああ、「レビューした」とは書いてなかったですね。済みません、レビューして、他の人に確認してもらうことも必要です。ちなみに、その「他の人」も、マルチスレッドは初めての経験でした。つまり、スレッド間でインスタンスを共有することによる危険を認識して、どうやって防ぐかという知識を持ち、適切に設計したので、「並列処理の一番基本的問題」は、未経験なのですよ。
> もっとも、設計の前にコードを書いたら、確かに経験が要りますね。それは認めます。が、そんなことしたら時間がもったいないので、勧められません。
> インドリさん、設計したことないんですか?そうか、コードを書いてから、そのコードによって考えに気づくのでしたね。コードが先ですね。聞くだけ野暮でした。失礼しました。
> でも、他の人に読んでもらう物を書くときは、ちゃんと設計してくださいね。
>
> そうそう、Objectさんもそうでしたが、「誤解している」というわりに、「どこを、どう、誤解しているか」の説明はないんですね。私はいったい、何を、誤解していると思っているのですか?私には、インドリさんこそ、並列処理の表面的なことだけを知って、知ったかぶりしているように見えるのですが。メモリリークとオーバーフローの件。番兵メソッドの件。StringCchCopyの件。ブロック化の件。値渡しと参照渡しの件。coutの件。とりあえず印象的だったのはこれだけですが、印象的な物だけでも1年ほどの間にこれだけあります。これだけの「間違い」を挽回するには、ちょっと「正しいことの実績」が、足りなくありませんか?
本当に日本語が余命人を相手にすると疲れます。
何度も指摘しておりますが、それすらも読んでいない。
分析と設計に経験がいらないというのは、SEに対して喧嘩を売っている態度ですね。
何事にも経験は必要です。
それに、貴方がたは「この基礎レベルを理解できなかった」のですから、経験が必要なのを貴方がた自身が証明しております。
それに、経験は必要ないと上から目線で書くのであれば、読者を馬鹿にしている事になります。
だから、分からない人がいるかもしれないから「経験が必要」だと柔らかい表現をしているのですが・・・
貴方は根本的なコミュニケーション能力がなさ過ぎです。
きっと、職場の同僚や上司は困っているのでしょうね。
それから、あのコメント荒らし達の指摘は(貴方もメンバーでしたよね)「根本から間違っています」
根本から間違ってお話しにならなりませんし、極力変な人は相手にするなと編集部から注意されていたので無視しておりましたが、他の読者の方に絡んだり、記事の内容を勝手に変えたりするので、目に余って注意しました。
coutの件にしてもそうですし、Sleepにしてもそうだし、とにかく集団で間違いをわめき、注意した読者に絡み、自分の間違いを認めたくなくてひたすらごねる・・・
そんな、迷惑行為を集団でするものですから、相手にしたくないのですが注意するしかありません。
間違いを認めたくなく、こうやってまた貴方がごねておりますが、基礎から指摘が間違っているのと、あの子供じみた荒らし行為については何時謝罪するのですか?
人にとやかく言う前に、大人の責任を取ってください。
※だから知らない事を指摘しているつもりになるなといっているのだが、何時になったら通じるのだろうか?
まぁ、無理でしょうがね。
過ちを認めなず、社会的常識を持たないグルーブですから。
この騒ぎについて説明を望む人が居ますので書きます。
はたから見ると、この狂った人たちとのやり取りの意味が分からないと思いますので解説します。
この人たちは、自身達が知らない事について「間違っている」と言って騒ぎ立てます。
そして、自身が間違っている事は途中で気付いても、こうやってごねて誤魔化そうとします。
事の本質は「知らない事を間違っていると指摘する」点にあります。
並列処理を知らないのにもかかわらず、並列処理についての記事を間違っていると集団で騒ぎ、Sleep命令の仕様や、WindowsOSがリアルタイムOSでない事を知らずに騒いだり、自分たちと違う事を言った普通の人に絡んだり・・・と、とにかく間違った認識のもと人に間違っていると絡みます。
この人たちは話しが通じないので、極力無視をする方向性で対処しているのですが、数の暴力で間違っている事を正しいと他者に錯覚させる可能性がありますし、放置すると他の人に絡んだりするのでたまに注意しております。
注意しておかないと、誤解する人もいますし、絡まれた人が可哀そうですからね。
しかし、WindowsをリアルタイムOSでないと知らなかったり、Sleep関数も知らなかったり、並列処理においてグローバル変数を極力避ける事を知らなかったり、本当に実務経験があるのかな?
集団で専門用語を並べたてて荒らしまわっておりますが、基礎的な事を知らない事は明白です。
皆様もこの人たちの事は無視して下さい。
もうそろそろ、私もスルー態勢に戻ります。
余りにも馬鹿々しいので余り相手にしたくないのですが、総括をする為に一応これについて書いておきます。
>インドリさん、設計したことないんですか?そうか、コードを書いてから、そのコードによって考えに気づくのでしたね。コードが先ですね。聞くだけ野暮でした。失礼しました。
でも、他の人に読んでもらう物を書くときは、ちゃんと設計してくださいね。
貴方が実務経験がない事がよくわかりました。
実務では実装から設計を考える必要がる場面があります。
例えば、実装を担当している会社から依頼があった場合、設計書と実装を比べる為に、実装から想定される設計も考える必要があります。
実務経験がなくて、分析・設計・実装が教科書通り、全て上手くいくと考えているようですが、実務ではそんなに綺麗に事は進みません。
> そうそう、Objectさんもそうでしたが、「誤解している」というわりに、「どこを、どう、誤解しているか」の説明はないんですね。私はいったい、何を、誤解していると思っているのですか?
貴方達が何度言っても分かっていないだけです。
この状態と同じ事が1年以上続いています。
ここまで読解能力がない人にどうやって説明すればいいものやら・・・
>私には、インドリさんこそ、並列処理の表面的なことだけを知って、知ったかぶりしているように見えるのですが。
並列処理について明らかに知らない人に言われても、説得力が全くありません。
知らない人がどうやって判断しているのやら。
>メモリリークとオーバーフローの件。
あの件もこの人達が勝手に誤解しているだけです。
>番兵メソッドの件。
番兵についての説明をするために一応記述したのですが、やはり分かっていなかったようですね。
>StringCchCopyの件。
ふぅ、この件も説明したのですが、読解能力がなくて、最後まで誤解しておりましたね。
困ったものです。
>ブロック化の件。
これはなんだろう?
ボックス化の間違いかな?
>値渡しと参照渡しの件。
確かに説明を間違えましたが、間違えを一度も許せないというのであれば、貴方達の間違えの多さはどうにかならないものですか?
>coutの件。
グローバルなリソースを並列的にアクセスしたら問題です。
これは基礎的な事であり、並列処理について知らないという事が、こういう所でばれるんですよね。
>とりあえず印象的だったのはこれだけですが、印象的な物だけでも1年ほどの間にこれだけあります。これだけの「間違い」を挽回するには、ちょっと「正しいことの実績」が、足りなくありませんか?
素晴らしい誤読・無恥さの証明ですね。
これだけの数を、誤読し間違って解釈している事に脱帽しました。
私はもっと覚えていますが、貴方達の読解能力はどうにかならないのですか?
これでお終い。
どうせ日本語が通じない相手に何を言っても無駄だと思いますが、他者の人が分かりやすいように書きました。
これを見れば、彼らが如何に読解能力と式ががなく、社会的常識もない事が分かるでしょう。
こんな人たちを相手にしないようにしてください。
このブログにこの手の人達の事について問い合わせをしないでください。
日本語が通じない人と会話するのも不可能ですし、余りにも誤読・曲解しているので説明するのも面倒です。
基礎から間違っており、読解能力がない人に何を言っても無駄です。
ブロック化の見当がついたので補足します。
おそらくtry系関数の事を言っているのでしょう。
並列処理は逐次処理とは違う色々な要因で、長時間稼働した時に問題が漸く発生する時があります。
そういった場合に、try系の関数を使って、ログを採ったりする時もありますし、より並列的に処理するために、プッシュされるのを待たずに他の処理を先に実行する場合があります。
彼らはtry系関数が何のためにあるのか分かっていなかったのでしょう。
それでtry系関数の解説を書いた事について難癖をつけていたのでしょうが、必要がないものを実装するわけはありません。
try系の関数の存在を知らないで実務にトライしたら大変な事になります。
それにも関らず、try系の関数を紹介しない方が可笑しいのです。
その方が記事として問題があります。
> 混乱しているのは酷く読解能力がない証拠。
え〜っと、すみません、私は、あの記事は、「初心者に対しての説明」だと理解しているのですが、あいや、インドリさん自身がそう書いていらっしゃるのですが、違うのでしょうか。
で、私は、「初心者が混乱しないように」と申しているのですが、私が混乱していると、誤解なさっているのでしょうか?まぁ、混乱してないとはいいきれないですね。インドリさんが説明されている物と、私が理解している物が違っているようですので。もっと、きちんとした知識があって、それを表現する方法が下手なのだと思っていたのですが、どうも、そうでもないようです。自分の知識を過信されているように思われます。
ん〜、こう、あれでしょ。「ローカル変数にすればよい」という結論があって、そういう説明をしたいためにコードを作っていますよね?それがために、説明が足りない、説明の設計がされていないと、申しているのですが。全てが、「結論ありき」で、その為のコードを組んでいませんか?
> やはり、分かっていない。
だから、インドリさんは、私や、その他の指摘をした方々が、どこをわかっていないとおっしゃっているのでしょう?私としては、自分の非を認めたくないために相手がわかっていない「ことにしたい」としか映らないのですが。以前から、「わかっていないといっている箇所を具体的にしろ」と指摘されていますよね。なぜできないのでしょう?
いや、もっとも、説明があるところでも、その説明が、「わかっちゃいない」のですが。
> それに、あれは(よくわからんけど指摘しているつもりの場所を想像してみた)どちらかというとアトミックなコードを指しています。
では、具体的に、端的にお尋ねしますが、
cout << 1;
cout << 2;
cout << 3;
と3行で書くのと、
cout << 1 << 2 << 3;
と書くのには違いがある、とお考えですか?
CodeZine では、「違いがある」との解釈しかできないコメントをされているのですが、その理解(インドリさんが「違いがある」と考えられている)でかまいませんか?ここでは書くのが面倒なので 1,2,3 としますが、インドリさんが十分だと考えるほど長い文字列であったり、要素数であってかまいません。
> coutの様なグローバルなオブジェクトは、
う〜ん、ここで「グローバルなオブジェクト」を、どの様な意味で使われていますか?
例えば。複数のポートから電文を受信します。これらのポートは、おのおの別スレッドで監視します。しかし、電文を処理するスレッドは1つです。そこで、各スレッドに共通のコンテナ オブジェクトを使用する事とします。このコンテナは、メイン スレッドの「ローカル変数」として宣言し、各スレッドに参照/変更出来るように通知します。この時、「ローカル変数として宣言した共通のコンテナ オブジェクト」は、「グローバル」ではないでしょうか。
えっと、「ローカルな」オブジェクトとして宣言しても、各スレッドが参照するのは、1つのインスタンスです。なので、「グローバルな」オブジェクトだ、という意味です。グローバル変数として宣言するわけではありません。
cout について、というよりその元である、basic_stream ですね。一応、サンマクロシステムズと、マイクロソフト、GNU のコンパイラでは、スレッドセーフであることが保障されています。また、POSIX が iostream にスレッドセーフであることを要求しますので、POSIX 準拠のコンパイラは、スレッドセーフです。GNU は、この、POSIX 準拠によるスレッドセーフです。
そして、マイクロソフトのリファレンスには、こう注記されています。「However, this can result in the output from the two threads being intermixed.」(しかしながら、2つのスレッドからの出力が混入するという結果になります)。
サンマイクロシステムズのリファレンスにはもう少しはっきりと、「スレッドセーフな関数だけを使用したからといって、アプリケーションがスレッドセーフになるわけではありません。アプリケーションがスレッドセーフであることは、開発者が保障しなければなりません」と書かれているそうです。
つまり、インドリさんは、「cout の operator<< というメソッドがスレッドセーフであること」と、「それを使ったアプリケーションがスレッドセーフであること」を、混同していると思われます。
> 並列関係の書籍を見たら書いてあるはずだし
はい、リファレンスに書いてあります。
http://msdn.microsoft.com/en-us/library/c9ceah3b(VS.100).aspx
http://dlc.sun.com/pdf/820-1213/820-1213.pdf
http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html
「cout がスレッドクリティカルである」と書いてある書籍があるなら、ぜひ紹介してください。しかし、「スレッドセーフな関数を使ったからといって、アプリケーションがアプリケーションの仕様通りに動作するわけではない」ということであるなら、同意します。たとえば、concurrent_queue であっても、cout と同様に、複数のスレッドから入力を行うと、どの様な順序でキューインされるかは不明ですからね。
もっとも、C++ では規定されていないので、標準 C++ 規程ではスレッドクリティカルです。しかし、スレッドを扱うことを前提としているライブラリは、スレッドセーフに作られていると言って問題はないでしょう。例えば、サンの場合は問題があるバージョンを「古い標準ライブラリ」として、言及しています。マイクロソフトは1999年頃でさえ strtok をスレッドセーフに作っていますから、問題はなかったでしょう。
> 分析と設計に経験がいらないというのは、SEに対して喧嘩を売っている態度ですね。
インドリさんは「コードからバグを見つけるのに経験がいる」と書かれていますよ?私は、「問題と解決方法を把握していれば、設計をするのに経験は要らない」と書いているのですけど。そこに「コードからバグを見つけるのに経験がいる」は、飛躍ではないでしょうか。じゃなくて、「読解力がない」ですね、すみません。
あと、勝手にグループ化するのはやめてください。私も、「な!のページ」にあげられているのは、ご存じないですか?私は、相手がεπιστημηさんであっても、間違えていると思えば指摘しますよ。同じように、私が間違えていれば、皆、遠慮なく指摘してくださいます。
すなわち、コメントがないのは賛意。間違いは、訂正をしてくれます。もっとも、インドリさんの記事については、あまりにも「間違っていない」という主張が激しいので、放置気味ですが。
> >メモリリークとオーバーフローの件。
> あの件もこの人達が勝手に誤解しているだけです。
用意された領域を超えて使用してしまうオーバーフローと、確保しながら解放しないリークを混同しているのはインドリさんですが?その混同に対して「違う」と言っても、「違うもんか」と言い張ったのは、インドリさんですよ?何を誤解してると仰っていますか?
また、「本文に示されているコードではメモリリークは発生しない」というのは、販社のサポートの見解です。その見解に対して、「違う」と仰るのでしょうか。いえ、検証したときのコードと掲載されているコードが違うという、あまりにもお粗末で、すぐに作成できるはずの管理システムが出来上がっていれば撲滅できているはずのミスは、その後に判明していますが、それは「この人達が勝手に誤解している」ではなく、「私(インドリさん)がちゃんとした検証をしておりませんでした」でしょう。ここを間違えると、全て他人が悪いことになっちゃいますよ。
> >番兵メソッドの件。
> 番兵についての説明をするために一応記述したのですが、やはり分かっていなかったようですね。
いえ、番兵についての説明は、「次の回」でしょ。番兵が「いない」コードに対して、番兵が「いるlような書き方をしてしまった。で、「手元のコードは修正したが、ブログは更新していなかった」と、誤りを認めたのはインドリさんなのですが。もっとも、必死で繰り返されている説明は、「未満」の意味が正しく理解できていないように見受けられましたが。
> >StringCchCopyの件。
> ふぅ、この件も説明したのですが、読解能力がなくて、最後まで誤解しておりましたね。
> 困ったものです。
なにを、誤解しているのでしょう?StringCchCopy は、コピー先の大きさを文字数で指定して、その文字数を超えない範囲でコピーを行います。よって、「コピー先の文字数」を間違えない限り、コピー先の大きさを超えたコピーが行われることはありません。それを「超えてコピーする」と仰っているのは、インドリさんなのですが。
もちろんこれは、アプリケーションの仕様にとって、間違っている状態を作り出します。つまり、「文字数が足りない状態」です。これは、「アプリケーションの仕様」にとっては間違いですが、オーバーフローをおこすような「危険」な状態ではありません。しかし、インドリさんの書き方では、これによって「メモリリークが起きる」と書かれています。「確保した物を解放しないリーク」と、「用意された領域を超えて使用するオーバーフロー」を混同している上、大きさを間違えなければオーバーフローが発生しないものに対して「発生する」と言い張っているのは、インドリさんですけど。つまり、「間違って覚えている」物に対して「違う」と指摘されているから、「誤解している」と、誤解されているのではないかと思います。
> >値渡しと参照渡しの件。
> 確かに説明を間違えましたが、間違えを一度も許せないというのであれば、貴方達の間違えの多さはどうにかならないものですか?
え〜っと、私は、「間違ってますよ」「いや間違ってない」「間違ってますって」「い〜や、間違ってない」「こういう理由で間違っています」「はい、間違っていました」の例としてあげているのですが?ブログの方に「IL によるとボックス化は行われていない」と書いたのに、私に「やっぱりボックス化の理解が足りていない」と言い放ったのはインドリさんですよ?「どこでボックス化が使われていますか?」という指摘がなければ、間違っている事を今でも認めませんよね。「間違っている例」ではなく、「間違っている物を間違っていないと強固に主張した例」です。両者には違いがあるので、「間違わないでください」。
というか。そうか、「参照渡し」の理解も、やはり間違っていましたか。参照渡しが何故「書類と大まかに言う」になるのか、意味不明だったのですが(C++の方でεπιστημηさんが指摘されていること)。間違いを認めていただき、ありがとうございます。
> >coutの件。
> グローバルなリソースを並列的にアクセスしたら問題です。
> これは基礎的な事であり、並列処理について知らないという事が、こういう所でばれるんですよね。
え〜っと、「問題」と見るスコープの問題です。まぁ、上に書いたからいいや。
> ブロック化の件
ああ、ごめんなさい、これは、書き間違いです。「ボックス化の件」でした。混乱させて申し訳なかったです。つまり、「参照渡し」の記事には、「参照渡し」と「継承元へのキャスト」を混同しているという問題と、「全ての型の継承元である Object へのキャスト」と「ボックス化」を絡めようとして失敗した問題、2つの問題があるということです。また、float と double の変換ではボックス化は発生しないので、ボックス化についても理解を間違っていると思われます。
try_push の「ブロック」については、インドリさんが「何が、何を、どの様にブロックする」と書かれているのか、よく分かりません。本文に書いてあることは、「push メソッドが、プロセスを停止する」と書いてあるように読めます。しかし、コメントでは、「try から抜けてこない」としか書いていないように思われます。つまり、本文とコメントの内容に矛盾が見られます。また、皆さんの指摘は、「try_push したところで、空きが出来るまで待っていたら push と同じでしょ」ということです。インドリさんが本文で示されている例は try_push が成功するまで待っていますから、push と置き換えたところで差異はありません(あくまで、インドリさんが CodeZine の記事本文で示されているコードは、ですよ)。
もっと簡潔に書くと、「なぜ、待たないコードを提示しないのか」ということです。try_push に失敗したらそのまま次の処理に行くコードが書いてあれば、皆納得する、ということです(επιστημηさんがコメントで書かれているコード)。
> ログを採ったりする時もありますし
何かあった場合に原因を探るためにログを仕込みますが、そのログが try_push によって「取らないこともある」のであれば、設計ミスです。ここは、スレッドに番号を振って、スレッド番号と共に必ず記録するようにするでしょう。もちろん、ディスクが一杯で書き出せないからバッファも空かないという状況下では、困ったことになりますが。
これ、7日から練っているんですよね。いやもう、どう言ったら通じるのか、ホトホト困りますよ。いい加減、「間違えているかもしれない」という視点を持ってください。