並行プログラミングに関連するこれらの言葉を聞いたことがありますが、それらの違いは何ですか?
並行プログラミングに関連するこれらの言葉を聞いたことがありますが、それらの違いは何ですか?
回答:
ロックは、1つのスレッドだけがロックされた部分に入ることを許可し、ロックは他のプロセスと共有されません。
mutexはロックと同じですが、システム全体(複数のプロセスで共有)にすることができます。
セマフォは、ミューテックスと同じことが、スレッドのx個が入力することができ、これは、CPUの数を制限するIOまたは同時に実行集中タスクをRAMへ例のために使用することができます。
mutexとセマフォの違いに関する詳細な投稿については、こちらをご覧ください。
また、任意の時点で無制限のリーダーまたは1つのライターを許可する読み取り/書き込みロックもあります。
これらの言葉に関しては多くの誤解があります。
これは以前の投稿(https://stackoverflow.com/a/24582076/3163691)からのものです。
1)クリティカルセクション = 1つのプロセス内で他の多くのスレッドから1つのアクティブスレッドのみを実行できるようにするために使用されるユーザーオブジェクト。他の選択されていないスレッド(@このオブジェクトを取得)は、スリープ状態になります。
[プロセス間機能なし、非常にプリミティブなオブジェクト]。
2)ミューテックスセマフォ(別名ミューテックス) = さまざまなプロセス間で、他の多くのスレッドから1つのアクティブスレッドのみを実行できるようにするために使用されるカーネルオブジェクト。他の選択されていないスレッド(@このオブジェクトを取得)は、スリープ状態になります。このオブジェクトは、スレッドの所有権、スレッドの終了通知、再帰(同じスレッドからの複数の「取得」呼び出し)、および「優先順位の逆転回避」をサポートします。
[プロセス間機能、非常に安全に使用できる、一種の「高レベル」同期オブジェクト]。
3)セマフォ(別名セマフォ)をカウントする = 他の多くのアクティブスレッドのグループの実行を許可するために使用されるカーネルオブジェクト。他の選択されていないスレッド(@このオブジェクトを取得)は、スリープ状態になります。
[ただし、次の 'mutex'属性が欠けているため、プロセス間機能の使用は安全ではありません:スレッド終了通知、再帰?、 '優先順位逆転回避?'など]。
4)そして今、「スピンロック」について話します、最初にいくつかの定義:
クリティカル領域= 2つ以上のプロセスで共有されるメモリの領域。
Lock =値が「クリティカルリージョン」への入り口を許可または拒否する変数。(単純な「ブールフラグ」として実装できます)。
ビジー待機=ある値が現れるまで、変数を継続的にテストします。
最終的に:
スピンロック(別名スピンロック) = ビジー待機を使用するロック。(ロックの取得は、xchgまたは同様のアトミック操作によって行われます)。
[スレッドスリープなし。主にカーネルレベルでのみ使用されます。ユーザーレベルのコードには非効率的です。
最後のコメントとしてはわかりませんが、上記の最初の3つの同期オブジェクト(#1、#2、および#3)がこの単純な獣(#4)を実装の一部として利用していることには、大きな見返りがあります。
良い一日を過ごしてください!。
参照:
-Qing LiとCaroline Yaoによる組み込みシステムのリアルタイムコンセプト(CMP Books)。
-Andrew Tanenbaum(Pearson Education International)による最新のオペレーティングシステム(3番目)。
-Jeffrey Richter(Microsoftプログラミングシリーズ)によるMicrosoft Windows用プログラミングアプリケーション(第4回)。
ほとんどの問題は、(i)ロックのみ、(ii)セマフォのみ、...、または(iii)両方の組み合わせを使用して解決できます。お気づきかもしれませんが、どちらも非常に似ています。どちらも競合状態を防ぎ、どちらもacquire()
/ release()
オペレーションを実行し、どちらも0個以上のスレッドをブロック/疑わしくします...実際、重大な違いは、それらがどのようにロックおよびロック解除されるかにのみあります。
両方のロック/セマフォでacquire()
、プリミティブが状態0のときに呼び出しを試みると、呼び出しスレッドが中断されます。ロックの場合-ロックを取得する試みは状態1で成功します。セマフォの場合-状態{1、2、3、...}でロックを取得する試みは成功します。
状態が0のロックの場合、以前にを呼び出していたのと同じスレッドacquire()
がreleaseを呼び出すと、解放は成功します。別のスレッドがこれを試みた場合-何が起こるか(通常、その試みは無視されるか、エラーがスローされます)は、実装/ライブラリーに依存します。状態0のセマフォの場合、任意のスレッドが解放を呼び出すことができ、解放は成功します(以前にどのスレッドが獲得を使用してセマフォを状態0にしたかに関係なく)。
前述の説明から、ロックには所有者の概念(リリースを呼び出すことができる唯一のスレッドは所有者)があることがわかりますが、セマフォには所有者がありません(どのスレッドもセマフォでリリースを呼び出すことができます)。
多くの混乱を引き起こすのは、実際には、これらはこの高レベルの定義の多くのバリエーションであることです。
考慮すべき重要なバリエーション:
acquire()
/は何release()
と呼ばれるべきですか?-[ 大幅に異なります]これらはあなたの本/講師/言語/ライブラリ/環境に依存します。
いくつかの言語がこれらの詳細にどのように答えるかに注意するクイックツアーがあります。
pthread_mutex_t
。デフォルトでは、他のプロセス(PTHREAD_PROCESS_PRIVATE
)と共有できませんが、ミューテックスにはpsharedと呼ばれる属性があります。設定すると、ミューテックスはプロセス間で共有されます(PTHREAD_PROCESS_SHARED
)。sem_t
。ミューテックスと同様に、セマフォは多数のプロセスのスレッド間で共有したり、1つの単一プロセスのスレッドに対してプライベートに保つことができます。これは、に提供されるpshared引数に依存しsem_init
ます。threading.RLock
)主にC / C ++と同じであるpthread_mutex_t
S。どちらも再入可能です。これは、それらをロックしたのと同じスレッドによってのみロック解除できることを意味します。これは、sem_t
セマフォ、threading.Semaphore
セマフォ、およびtheading.Lock
ロックが再入可能ではない場合です。これは、任意のスレッドがロックのロック解除/セマフォのダウンを実行できる場合です。threading.Semaphore
)ほとんど同じですsem_t
。をsem_t
使用しても、スレッドIDのキューは、ロックされているスレッドをロックしようとしたときにスレッドがブロックされた順序を記憶するために使用されます。スレッドがセマフォのロックを解除すると、キュー内の最初のスレッド(存在する場合)が新しい所有者として選択されます。スレッド識別子がキューから削除され、セマフォが再びロックされます。ただし、threading.Semaphore
では、キューの代わりにセットが使用されるため、スレッドがブロックされた順序は保存されません。セット内のどのスレッドも次の所有者として選択される場合があります。java.util.concurrent.ReentrantLock
)主にC / C ++と同じであるpthread_mutex_t
の、そしてPythonのthreading.RLock
それはまた、リエントラントロックを実現することができます。プロセス間でのロックの共有は、JVMが仲介者として機能するため、Javaでは困難です。スレッドが所有していないロックを解除しようとすると、IllegalMonitorStateException
がスローされます。java.util.concurrent.Semaphore
)ほとんど同じであるsem_t
とthreading.Semaphore
。Javaセマフォのコンストラクタは、待機中のスレッドを格納するためにセット(false)とキュー(true)のどちらを使用するかを制御する公平性ブールパラメータを受け入れます。 理論的にはセマフォがよく議論されますが、実際にはセマフォはあまり使われていません。セマフォは1つの整数の状態のみを保持するため、多くの場合、柔軟性に欠け、一度に多くが必要になるため、コードの理解が困難になります。また、どのスレッドもセマフォを解放できるという事実は、望ましくない場合があります。代わりに、よりオブジェクト指向の/より高いレベルの同期プリミティブ/「条件変数」や「モニター」などの抽象化が使用されます。
見てみましょうマルチスレッドのチュートリアルジョンKopplinによると。
「スレッド間の同期」セクションでは、イベント、ロック、ミューテックス、セマフォ、待機可能タイマーの違いについて説明しています
ミューテックスは、共有リソースへの相互排他的アクセスを調整するためのスレッドを可能に、一度に一つのスレッドが所有することができます
クリティカルセクションオブジェクトは、ミューテックスオブジェクトによって提供されるものと同様の同期を提供しますが、クリティカルセクションオブジェクトは単一プロセスのスレッドによってのみ使用できます。
ミューテックスとクリティカルセクションのもう1つの違いは、クリティカルセクションオブジェクトが現在別のスレッドによって所有されている場合、
EnterCriticalSection()
所有権を無期限に 待機するのに対しWaitForSingleObject()
、ミューテックスで使用されるはタイムアウトを指定できることです。セマフォは、同時に共有リソースにアクセスしているスレッドの数を制限し、ゼロといくつかの最大値との間のカウントを維持します。
私はそれを例でカバーしようとします:
ロック:使用lock
する1つの例は、アイテム(一意のキーが必要)が追加される共有ディクショナリです。
ロックにより、別のスレッド(クリティカルセクションにある)が既にこのチェックに合格し、アイテムを追加している間に、ディクショナリにあるアイテムをチェックするコードのメカニズムに1つのスレッドが入りません。別のスレッドがロックされたコードを入力しようとすると、オブジェクトが解放されるまで待機(ブロック)されます。
private static readonly Object obj = new Object();
lock (obj) //after object is locked no thread can come in and insert item into dictionary on a different thread right before other thread passed the check...
{
if (!sharedDict.ContainsKey(key))
{
sharedDict.Add(item);
}
}
セマフォ: 接続のプールがあるとしましょう。セマフォが接続を取得するのを待つことで、単一のスレッドがプール内の1つの要素を予約する場合があります。次に接続を使用し、作業が完了するとセマフォを解放して接続を解放します。
私が大好きなコード例は、@ Patricによって与えられたバウンサーの1つです -ここでそれは行きます:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace TheNightclub
{
public class Program
{
public static Semaphore Bouncer { get; set; }
public static void Main(string[] args)
{
// Create the semaphore with 3 slots, where 3 are available.
Bouncer = new Semaphore(3, 3);
// Open the nightclub.
OpenNightclub();
}
public static void OpenNightclub()
{
for (int i = 1; i <= 50; i++)
{
// Let each guest enter on an own thread.
Thread thread = new Thread(new ParameterizedThreadStart(Guest));
thread.Start(i);
}
}
public static void Guest(object args)
{
// Wait to enter the nightclub (a semaphore to be released).
Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
Bouncer.WaitOne();
// Do some dancing.
Console.WriteLine("Guest {0} is doing some dancing.", args);
Thread.Sleep(500);
// Let one guest out (release one semaphore).
Console.WriteLine("Guest {0} is leaving the nightclub.", args);
Bouncer.Release(1);
}
}
}
ミューテックスそれはかなりSemaphore(1,1)
広く、しばしばグローバルに使用されます(アプリケーション全体でそうでない場合は間違いなくlock
より適切です)。Mutex
グローバルにアクセス可能なリストからノードを削除するときは、globalを使用します(ノードを削除している間、最後に別のスレッドに何かを実行してもらいたい)あなたが取得するとMutex
別のスレッドの試行が同じを取得する場合Mutex
、それは、取得した同じスレッドまでスリープ状態に置かれるMutex
のリリースにそれを。
グローバルミューテックスを作成する良い例は@deepeeです
class SingleGlobalInstance : IDisposable
{
public bool hasHandle = false;
Mutex mutex;
private void InitMutex()
{
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
mutex = new Mutex(false, mutexId);
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
mutex.SetAccessControl(securitySettings);
}
public SingleGlobalInstance(int timeOut)
{
InitMutex();
try
{
if(timeOut < 0)
hasHandle = mutex.WaitOne(Timeout.Infinite, false);
else
hasHandle = mutex.WaitOne(timeOut, false);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
}
catch (AbandonedMutexException)
{
hasHandle = true;
}
}
public void Dispose()
{
if (mutex != null)
{
if (hasHandle)
mutex.ReleaseMutex();
mutex.Dispose();
}
}
}
次に次のように使用します:
using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
//Only 1 of these runs at a time
GlobalNodeList.Remove(node)
}
これにより時間を節約できることを願っています。
ウィキペディアには、セマフォとミューテックスの違いに関するすばらしいセクションがあります。
ミューテックスは基本的にバイナリセマフォと同じものであり、同じ基本実装を使用する場合があります。それらの違いは次のとおりです。
mutexには、mutexをロックしたプロセスである所有者の概念があります。mutexをロックしたプロセスだけがロックを解除できます。対照的に、セマフォには所有者という概念がありません。どのプロセスでもセマフォのロックを解除できます。
セマフォとは異なり、ミューテックスは優先順位の反転の安全性を提供します。mutexは現在の所有者を知っているため、より優先度の高いタスクがmutexで待機を開始するたびに、所有者の優先度を上げることができます。
ミューテックスは、ミューテックスを保持しているプロセスが誤って削除されないように、削除の安全性も提供します。セマフォはこれを提供しません。
私の理解では、ミューテックスは単一のプロセス内でのみ使用できますが、セマフォは複数のプロセス間および対応するスレッドのセット間で使用できるのに対し、その多くのスレッドで使用できます。
また、mutexはバイナリ(ロックまたはロック解除)ですが、セマフォにはカウントの概念、または複数のロックとロック解除要求のキューがあります。
誰かが私の説明を確認できますか?私はLinux、特にカーネル2.6.32を使用するRed Hat Enterprise Linux(RHEL)バージョン6のコンテキストで話しています。
LinuxバリアントのCプログラミングを例のベースケースとして使用する。
ロック:
•通常、ロックまたはアンロックされた、動作中の非常に単純な構成バイナリ
•スレッドの所有権、優先度、順序付けなどの概念はありません。
•通常は、スレッドがロックの可用性を継続的にチェックするスピンロック。
•通常、アトミック操作に依存します(例:テストと設定、比較とスワップ、フェッチと追加など)。
•通常、アトミック操作にはハードウェアサポートが必要です。
ファイルロック:
•通常、複数のプロセスを介してファイルへのアクセスを調整するために使用されます。
•複数のプロセスが読み取りロックを保持できますが、単一のプロセスが書き込みロックを保持している場合、他のプロセスは読み取りまたは書き込みロックを取得できません。
•例:flock、fcntlなど。
ミューテックス:
•Mutex関数呼び出しは通常、カーネル空間で機能し、システムコールを引き起こします。
•所有権の概念を使用します。mutexを現在保持しているスレッドだけがロックを解除できます。
•Mutexは再帰的ではありません(例外:PTHREAD_MUTEX_RECURSIVE)。
•通常、条件変数との関連付けで使用され、pthread_cond_signal、pthread_cond_waitなどの引数として渡されます。
•一部のUNIXシステムでは、すべてのシステムで強制されているわけではありませんが、複数のプロセスでmutexを使用できます。
セマフォ:
•これは、値がゼロを下回ることを許可されていないカーネルが維持する整数です。
•プロセスの同期に使用できます。
•セマフォの値は、1より大きい値に設定できます。この場合、値は通常、使用可能なリソースの数を示します。
•値が1および0に制限されているセマフォは、バイナリセマフォと呼ばれます。
Supporting ownership
、maximum number of processes share lock
およびはmaximum number of allowed processes/threads in critical section
、一般的な名前がの並行オブジェクトの名前/タイプを決定する3つの主要な要素ですlock
。これらの因子の値は2値(2つの状態)であるため、3 * 8の真実のような表にまとめることができます。
X Y Z Name
--- --- --- ------------------------
0 ∞ ∞ Semaphore
0 ∞ 1 Binary Semaphore
0 1 ∞ SemaphoreSlim
0 1 1 Binary SemaphoreSlim(?)
1 ∞ ∞ Recursive-Mutex(?)
1 ∞ 1 Mutex
1 1 ∞ N/A(?)
1 1 1 Lock/Monitor
このテーブルを自由に編集または拡張してください。編集可能にするために、ASCIIテーブルとして投稿しました。