マルチスレッド処理とか調べていると、セマフォ、ミューテックス、モニターといった同期機構達の名前を良く目にします。違いが良くわからぬまま使っているのは良くないと思い立って復習してみたものの…こんがらかってきた。難しい。
以下、そのまとめ。全般的に用語があやしいので正しい用語を知ってたら教えてください。
やはりこの二つの違いが難しいです。思いこみが入ってる可能性大なのでご指摘は大歓迎です。
ミューテックス(MUTual EXclusion)はロックまたはアンロックの二状態を持つ同期機構です。ロックされているミューテックスを他の人がロックしようとすると、他の人はロックを拒否されるか、ロックが解除されるまで待ってからロックします。ロック操作にはいくつかの概念があります。
ミューテックスについてはこんなもんでしょうか?次、セマフォいってみよう。
セマフォ(Semaphore)にはロック/アンロックの概念はありません。あるのは P操作(セマフォが0でなければ数字を1減らす、0ならば待つ)と、V操作(セマフォをとにかく1増やす)です。ミューテックスは複雑な型になり得ますが、セマフォは整数値で実装可能でしょう。実装したこと無いけど。
セマフォはある区間(同じセマフォを対象とするP操作とV操作の間)に同時に何人入れるか?だけを制御します。
例えるならば、食堂で料理を載せるトレーでしょうか。食堂の入口で店員(セマフォ)にトレー(セマフォの値)をもらい(P操作)、食事した後、出口でトレーを店員に返す(V操作)というルールです。食堂にトレーが3枚しかなければ、一度に食事できる人は3人(スレッドやプロセス)に制限できるという仕組みです。
チケットの枚数(セマフォの初期値)を変えれば、ミューテックスと等価なセマフォも作れます。二値セマフォ(0か1しか値を取らないセマフォ)と言うそうですが、P操作がロックで、V操作がアンロックに相当します。
しかしセマフォにはミューテックスのような所有権、再帰といった概念はありません。自分のロックが誰かに壊されてしまう可能性(アンロックのときに異常な状態になるので検知はできますが…)や、ロック区間で再帰すればデッドロックに陥って自爆することがある。ってことです。
もちろんセマフォに所有権付けたって、ミューテックスの所有権がなくたって一向に構いません。世の中を見ても、実装によって同期機構の動作はバラバラです。同期機構って何だかわからないー!と感じる主因は単に「実装依存が多すぎる」だけかもなあ…。
ミューテックスとセマフォの実装の例として、Linuxのpthread(POSIX threadの略?)mutexとPOSIXセマフォの説明を見ます。pthread mutexはその名の通りスレッド間のみの同期を取る機構であり、POSIXセマフォはプロセス間共有ができる違いが大きいでしょう。
POSIXセマフォでは名前付きと無名を選べます。名前を付けるとファイルとして見えるのも大きな特徴でしょう。これはあくまでもPOSIXが規定する機能で、セマフォがみんなそうなっているわけではありません。しつこくて申し訳ないです。
一方pthread mutexはというと、基本的には二値セマフォです。しかし所有権チェック&デッドロックのチェックや、再帰ロックが可能になるオプションを指定できます。しかし 〜NP(non portableかな?) という名前を見るに、恐らくPOSIX準拠じゃない機能です。
Javaにはセマフォとミューテックスとはまた別にsynchronizedという別の同期機構(モニタというらしい)が備わっていますが、Wikipediaによればモニタはロックで実現できます。奇遇だね俺もそんな気がするよっ、ってことでスルー。
JavaのミューテックスはLockインタフェースの実装クラス(ReentrantLock, ReentrantReadWriteLock)が相当します。どちらも所有権の概念と、再帰ロックの概念を持っています。
他にも公平なロックという概念をオプションとして提供しています。公平なロックは上記の説明で出てませんでしたねえ。あれまー…。簡単に説明します。
ある一つのミューテックスをロックして仕事してアンロックする、という動きを繰り返しているAさん、Bさん、Cさんの3人がいるとします。3人が常に一つのミューテックスを欲しがっていますが、Aさんが偶然何度もロックを取得してしまうと、BさんやCさんはその間全く動けない状態に陥ります。
このときBさんやCさんは飢餓状態に陥っている、と言います。飢餓状態が起きないことを保証するロックの配り方、それが公平なロックです。
ReadWriteLockは多数の読み出し側(Reader)と少数の書き込み側(Writer)がいるときに有効なロックの戦略です。ReadLock(ReentrantReadWriteLock#getReadLock() で取得する)とWriteLock(ReentrantReadWriteLock#getReadLock() で取得する)のペアで使用します。
ReadLockは特殊なロックで複数人が同時にロックできます。WriteLockはReadLockと他人のWriteLockに対して排他的です。そのためWriteLockはReadLockと同時にかかることはありません。
何言ってんだテメェは!って思ったそこの貴女、表にしまし…たらちょっと見づらかったので、リストにしました。ReadWriteLockは大きく3状態に分けられます。
同期機構においてはPOSIXよりJavaの方が何かと親切ではあります。しかし親切な機能は大概遅いというのもお忘れ無く。
この記事にコメントする
Wikipediaのヒドラジンの項目を見ていたら、何か違和感を覚えました。
今も何度か読み返しましたが、やはり違和感があります。どこかというと、第二段落のこの下り(2008年2月19日現在)です。
気化吸引、皮膚への接触ともに腐食をもたらし全身を骨までドロドロに溶かす。
ヒドラジンは強アルカリで毒性も強いらしいのですが「全身を骨までドロドロに…」は言い過ぎというか、辞典らしくないアホっぽい書き方に見えます。
編集履歴を見ると匿名の誰かがこの下り「だけ」をわざわざ書き足したようで、意図的なものとしか思えません。何かヒドラジンに嫌な思い出でもあったのかねえ?
ん、文句言う前に自分で直せよって?まあそういうなって…。
この記事にコメントする
15日の話になりますが、会社帰りの電車に乗ると機械の焦げるような臭いがしていました。臭いで鼻が痛くなったんでたまらず乗った方と逆のドアに逃げましたが、さらに焦げ臭さが増したので、隣の車両に避難しました。
電車を降りてから焦げ臭かった車両の横を通ったら、なんと外側も激しく焦げ臭い。下回りのどこかが焼けてるんじゃなかろうか?大丈夫なのかJR西日本。
この記事にコメントする
「スマブラ」って打ったらとんでもない変換になったのでそのままにしておく。
友人(Senaさん)の部屋でWiiのスマブラXをやりました。64版を数回やったことあるだけでスマブラを語るのも失礼な話ですが、正直あまり面白くないというか、前にあった爽快感が無いです。
立ち攻撃(方向キーを押さずに攻撃)と横攻撃(左右キー+攻撃)の使い分けがイライラします。64にも横攻撃ってあったっけ?あっても覚えてないってことは、さほどイライラするものではなかったのでしょうけど。
あと全体的に判定が辛いっていうか、意地悪というか。バランス調整なのか、難易度を上げたのか。なんというかびみょ〜な出来です。
しばらくやったら面白くなるのかなあとも思いますが、人の家のゲーム機を使い倒すのはさすがに気が引け…って相当入り浸ってるので今更言えたもんじゃないけどさw
この記事にコメントする
仕事で全く原因が分からずに苦労していた部分がついに解消した。原因に気づいたらなんてことないことなんだけど、気づくまでが長かったなあ。うーん、スッキリ。
基本的には、休みの日に仕事の内容は考えないようにしてますが、苦戦しているときほど気になって仕方ないです。そういうときはどうしても考えてしまいますね。先週辺りがまさにそんな感じでした。
同期と飲み会。参加してた一人が仕事で行き詰まってる部分があると言って、飲み会の間もずっと考え事をしていました。あの状態では酒もうまくなかろうなあ。
なんというか、先週の自分を見ているようです。彼の問題があと一息で解決することを願いつつ。ガンバれ。
この記事にコメントする
目次: Java
SunのサイトからJDKのソースコードがダウンロードできます。なんとタダです。JDKのソースを何に使うか?当り前ですがJavaのライブラリの大部分はJava言語で書いてあります(一部はC言語ですが)。Javaを作った人達が書いたコードはこれ以上ない極上のJavaのサンプルコードと言えましょう。
私のようなJava素人ですと、斜め読みしているだけで発見がいっぱいです。例えば自身のクラスのコンストラクタをthis(); で呼べることを初めて知りました。今までいちいちprivate void Initialize() とか作ってました……。
この記事にコメントする
加藤研のゼミが朝早くあるようなので、先生に会えるかと思って朝早く行ってみました。こんな早く来て、鍵が開いてなかったらどうしよう…と思ったのですが、博士課程なお二人が居たので事なきを得ました。
京都のお土産はつまんないので、意表をついて「ひよこ」をおみやげにしたらほぼ100%の人に「なんでひよこ?」って聞かれました。作戦成功でございます。
何か勢いでゼミにまで出てしまいました。テラナツカシス。
研究室で皆さんと話したり、IKeJI&まぶっちーの研究の話とかを聞いていたら楽しかったです。一年経った今も、加藤研はとても良いところだったなあと思います。
会社説明会で最後にちょろっと話しました。話が全く面白くなかったのか、皆さん怖い顔。こりゃ失敗か。
懇親会の会場を決める係だったのですが、決める際のすったもんだの割に、結局懇親会には5人しか来なかったので、決めても決めなくても何も変わらんのであった。悲しい…。
この記事にコメントする
初めての有給取りました。3連休に繋げて4連休にするという大胆な使い方を試みたので、何か困難が待ち受けているのかと思ったのですが、上司に聞いてみたら「ああ、いいよ」って感じであっさりOKくれました。
他の人に聞いたわけではないので何とも言えませんが、お客さんに支障が出るような休み方でなければ、何も言われないでしょう。きっと。
この記事にコメントする
大下さんと「宮廷のみやび 近衛家1000年の名宝」という特別展(東京国立博物館 平成館)を見に行きました。その名の通り近衛家という公家に伝わる様々な美術品が展示されています。
近衛家は、かつての摂関政治を牛耳り「日本は俺の物ですが何か?」と言い切った藤原家の流れを汲んでいる、いわゆる超名家ってやつです。一般人には縁もゆかりもありません。
中には「いよぉ、元気でやってる?」くらいの手紙も大層に飾ってあります。それでも書いた人が貴族とか天皇とか上皇ともなると、美術品の一種となるのでしょうね。
美術品はいまいち分からないものが多いのですが。今回見た中では近衛家熙(※1、※2)の「隷書心経」に感動しました。字がうますぎて、最初、印刷か何かだと思ったさ。家熙は何でも屋さんだったみたいですが、書家としてかなり有名みたいです。
賀茂人形や銀細工雛道具といった細かく小さい細工品が飾ってあるのを見ると、今も昔もそしてこれからも相も変わらず、日本人は小さくてかわいい物が大好きなんだなと思います。その形は変われども。国民性ですねえ。
(※1)このえ いえひろ [1667-1736] 、江戸時代の公家。Wikipedia「近衛家熙」の項を参照のこと。
(※2)(2/18更新)「ひろ」の字が環境によっては豆腐に…と書いていましたが、日記をアップデートした段階(EUC-JP -> UTF-8の変換)で潰れて出ていませんでした。諦めて当て字を書いておきます。
この記事にコメントする
目次: Java
このキーワードでピンと来た方はこの日記を読む必要はないと思います。
Genericsなクラスにcloneメソッドを作ろうとしてはまりました。以下のようなコードを書いたわけです。
class MyVector<T extends Cloneable> implements Cloneable {
T[] items;
public Object clone() {
MyVector<T> copy = new MyVector<T>();
for (int i = 0; i < items.length; i++) {
copy.items[i] = (T)(items[i].clone()); //error!!
}
return copy;
}
}
Cloneableを継承する型だと宣言したところでCloneableインタフェースにはclone() の定義がありません。コンパイラはこのコードを見てもTがpublicメソッドのclone() を持っているのか、いないのかコンパイル時に判断できません。
従ってこのコードを実行すると基底クラスのObjectクラスのclone() メソッド(privateメソッド)が呼ばれる可能性があります。そのためコンパイラは「(Objectの)clone() はpublicじゃないから呼べません」とエラーを出すのです。
clone() を呼ばずに、以下のようなコードに直せばコンパイルが通ります。しかしこのコードで生成されるTのコピーはあくまでも「シャローコピー」ですから、Tがシャローコピーでコピーしきれない要素を持っていたときに破綻します。
copy.add(get(i)); //OK
配列の要素まで「ディープコピー」をするには、Tにclone() 関数の定義を強制させる必要があります。これにNewCloneableとでも名前を付けますと、以下のようになります。
public interface NewCloneable extends Cloneable {
public Object clone();
}
class MyVector2<T extends NewCloneable> implements Cloneable {
T[] items;
public Object clone() {
MyVector2<T> copy = new MyVector2<T>();
for (int i = 0; i < items.length; i++) {
copy.items[i] = (T)(items[i].clone()); //OK
}
return copy;
}
}
新しく作ったMyVector2クラスは「ディープコピー」ができるようになりました。しかしこのクラスは全く使い物になりません。なぜならNewCloneableを継承するクラスは標準クラスライブラリに存在しないからです。つまり何を言っているのかというと、
MyVector<Integer> v1; //OK
MyVector2<Integer> v2; //error!!
MyVectorと同じ乗りでMyVector2を使おうとすると「IntegerはNewCloneableを実装してないからダメ」と怒られます。せっかくのGenericsなのに自分で作ったクラスしかぶち込めないんじゃ、ちょっとあんまりですよね。
それならと、Integerを継承してNewCloneableを実装したクラスNewIntegerを定義しよう!と思ってもIntegerはfinal宣言されていて継承できません。MyVector2はますます役立たずです。
結局はシャローコピーで我慢せよってことですかね。もしくはclone() なんか実装すんじゃねーよってことでしょうか…。
この記事にコメントする
| < | 2008 | > | ||||
| << | < | 02 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
| - | - | - | - | - | 1 | 2 |
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | - |
wiki
Linux JM
Java API
2002年
2003年
2004年
2005年
2006年
2007年
2008年
2009年
2010年
2011年
2012年
2013年
2014年
2015年
2016年
2017年
2018年
2019年
2020年
2021年
2022年
2023年
2024年
2025年
過去日記について
アクセス統計
サーバ一覧
サイトの情報合計:
本日: