.NETマルチスレッド(九)同時同期
5386 ワード
このセクションの主な内容は次のとおりです。
**単純ハイブリッドモード同期構造SimpleHybridLock**単純ハイブリッドモード同期構造スピンAnotherHybridLock**ハイブリッドモード同期構造、ManualResetEventSlim**ハイブリッドモード同期構造、SemaphoreSlim**BlockingCollection**
(5)簡単な混合モード同期構造
自分でSimpleHybridLockを実現
class SimpleHybridLock : IDisposable
{
private int userLock = 0;
private AutoResetEvent kernelLock = new AutoResetEvent(false);
public void Enter()
{
if (Interlocked.Increment(ref userLock) == 1) { return; }
kernelLock.WaitOne();
}
public void Leave()
{
if (Interlocked.Decrement(ref userLock) == 0) { return; }
kernelLock.Set();
}
public void Dispose()
{
kernelLock.Dispose();
}
}
//
SimpleHybridLock myLock = new SimpleHybridLock();
int result = 0;
int taskCount = 1000;
List taskList = new List();
for (int i = 0; i < taskCount; i++)
{
Task task = Task.Factory.StartNew(() =>
{
for (int j = 0; j < 1000; j++)
{
myLock.Enter();
result = result + 1;
myLock.Leave();
}
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine(result);
(6)簡単な混合モード同期構造スピン
自分でAnotherHybridLockを実現
class AnotherHybridLock : IDisposable
{
private int userLock = 0, ownThreadId = 0, ownCount = 0, spinCount = 4000;
private AutoResetEvent kernelLock = new AutoResetEvent(false);
public void Enter()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId == ownThreadId)
{
ownCount = ownCount + 1;
return;
}
SpinWait spinWait = new SpinWait();
for (int i = 0; i < spinCount; i++)
{
if (Interlocked.CompareExchange(ref userLock, 1, 0) == 0) { goto GotLock; }
spinWait.SpinOnce();
}
if (Interlocked.Increment(ref userLock) > 1)
{
kernelLock.WaitOne();
}
GotLock:
ownThreadId = threadId;
ownCount = 1;
}
public void Leave()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId != ownThreadId)
{
throw new SynchronizationLockException("Lock not owned by calling thread");
}
ownCount = ownCount - 1;
if (ownCount > 0)
{
return;
}
ownThreadId = 0;
if (Interlocked.Decrement(ref userLock) == 0)
{
return;
}
kernelLock.Set();
}
public void Dispose() { kernelLock.Dispose(); }
}
//
AnotherHybridLock myLock = new AnotherHybridLock();
int result = 0;
int taskCount = 1000;
List taskList = new List();
for (int i = 0; i < taskCount; i++)
{
Task task = Task.Factory.StartNew(() =>
{
for (int j = 0; j < 1000; j++)
{
myLock.Enter();
result = result + 1;
myLock.Leave();
}
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
Console.WriteLine(result);
(7)FCL独自のハイブリッドモード同期構造ManualResetEventSlim
FCL: Framework Class Library
ManualResetEventSlim【System.Threading.ManualResetEventSlim】
(1)有信号(2)無信号
「シグナル意図」に基づいて、適切なシナリオを選択
# , , ,
# , ,
# :ManualResetEventSlim,AutoResetEvent, CountdownEvent, or Barrier
private static readonly ManualResetEventSlim signal = new ManualResetEventSlim();
static void Main(string[] args)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(10 * 1000);
signal.Set(); // signal
});
Task.Factory.StartNew(() =>
{
signal.Wait(); // , ....
// ,signal , CPU
// ....
Console.WriteLine("hi");
});
Console.ReadLine();
}
(6)FCL独自のハイブリッドモード同期構築SemaphoreSlim
(1)共有リソースへの同時アクセスを制限するためのスレッド数(2)ハイブリッドモード構造は,可能な限り減らすためにスレッドコンテキストを切り替える.
// 3
private static readonly SemaphoreSlim signal = new SemaphoreSlim(3);
static void Main(string[] args)
{
for (int i = 0; i < 10; i++) // 10
{
Task.Factory.StartNew(() =>
{
signal.Wait(); // 3
// ....
// , ....
Console.WriteLine("hi");
Thread.Sleep(5 * 1000);
signal.Release(); //
});
}
Console.ReadLine();
}
BlockingCollection【System.Collections.Concurrent.BlockingCollection】生産スレッド、消費スレッド
この集合を消費するときは、渋滞を待つ必要があります.もしこの集合を消費するときは、待たなくてもいいですか?簡単な例では、UIが消費スレッドである場合、UIスレッドは待ち時間でキュー内の項目の詳細を処理することはできません.非同期キュー
初見TPL Dataflow library
private static readonly BlockingCollection blockQueue = new BlockingCollection();
Task.Factory.StartNew(() =>
{
int num = 10;
while (num > 0)
{
blockQueue.Add(num);
num = num - 1;
Thread.Sleep(1 * 1000);
}
//blockQueue.CompleteAdding(); //
});
//blockQueue.Add(3); // ,
//blockQueue.Take(); // 1
foreach (int num in blockQueue.GetConsumingEnumerable()) // ,
{
Console.WriteLine(num);
Thread.Sleep(2 * 1000);
}
Console.WriteLine(blockQueue.Count); // ,
Console.ReadLine();