SpinLock Struktúra
Definíció
Fontos
Egyes információk olyan, kiadás előtti termékekre vonatkoznak, amelyek a kiadásig még jelentősen módosulhatnak. A Microsoft nem vállal kifejezett vagy törvényi garanciát az itt megjelenő információért.
Egy kölcsönös kizárási zár primitív, ahol egy szál, amely megpróbálja beszerezni a zárolást, egy hurokban várakozik, amíg a zárolás elérhetővé nem válik.
public value class SpinLock
public struct SpinLock
[System.Runtime.InteropServices.ComVisible(false)]
public struct SpinLock
type SpinLock = struct
[<System.Runtime.InteropServices.ComVisible(false)>]
type SpinLock = struct
Public Structure SpinLock
- Öröklődés
- Attribútumok
Példák
Az alábbi példa bemutatja, hogyan használhatja a következőt SpinLock:
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class SpinLockDemo
{
// Demonstrates:
// Default SpinLock construction ()
// SpinLock.Enter(ref bool)
// SpinLock.Exit()
static void SpinLockSample1()
{
SpinLock sl = new SpinLock();
StringBuilder sb = new StringBuilder();
// Action taken by each parallel job.
// Append to the StringBuilder 10000 times, protecting
// access to sb with a SpinLock.
Action action = () =>
{
bool gotLock = false;
for (int i = 0; i < 10000; i++)
{
gotLock = false;
try
{
sl.Enter(ref gotLock);
sb.Append((i % 10).ToString());
}
finally
{
// Only give up the lock if you actually acquired it
if (gotLock) sl.Exit();
}
}
};
// Invoke 3 concurrent instances of the action above
Parallel.Invoke(action, action, action);
// Check/Show the results
Console.WriteLine("sb.Length = {0} (should be 30000)", sb.Length);
Console.WriteLine("number of occurrences of '5' in sb: {0} (should be 3000)",
sb.ToString().Where(c => (c == '5')).Count());
}
// Demonstrates:
// Default SpinLock constructor (tracking thread owner)
// SpinLock.Enter(ref bool)
// SpinLock.Exit() throwing exception
// SpinLock.IsHeld
// SpinLock.IsHeldByCurrentThread
// SpinLock.IsThreadOwnerTrackingEnabled
static void SpinLockSample2()
{
// Instantiate a SpinLock
SpinLock sl = new SpinLock();
// These MRESs help to sequence the two jobs below
ManualResetEventSlim mre1 = new ManualResetEventSlim(false);
ManualResetEventSlim mre2 = new ManualResetEventSlim(false);
bool lockTaken = false;
Task taskA = Task.Factory.StartNew(() =>
{
try
{
sl.Enter(ref lockTaken);
Console.WriteLine("Task A: entered SpinLock");
mre1.Set(); // Signal Task B to commence with its logic
// Wait for Task B to complete its logic
// (Normally, you would not want to perform such a potentially
// heavyweight operation while holding a SpinLock, but we do it
// here to more effectively show off SpinLock properties in
// taskB.)
mre2.Wait();
}
finally
{
if (lockTaken) sl.Exit();
}
});
Task taskB = Task.Factory.StartNew(() =>
{
mre1.Wait(); // wait for Task A to signal me
Console.WriteLine("Task B: sl.IsHeld = {0} (should be true)", sl.IsHeld);
Console.WriteLine("Task B: sl.IsHeldByCurrentThread = {0} (should be false)", sl.IsHeldByCurrentThread);
Console.WriteLine("Task B: sl.IsThreadOwnerTrackingEnabled = {0} (should be true)", sl.IsThreadOwnerTrackingEnabled);
try
{
sl.Exit();
Console.WriteLine("Task B: Released sl, should not have been able to!");
}
catch (Exception e)
{
Console.WriteLine("Task B: sl.Exit resulted in exception, as expected: {0}", e.Message);
}
mre2.Set(); // Signal Task A to exit the SpinLock
});
// Wait for task completion and clean up
Task.WaitAll(taskA, taskB);
mre1.Dispose();
mre2.Dispose();
}
// Demonstrates:
// SpinLock constructor(false) -- thread ownership not tracked
static void SpinLockSample3()
{
// Create SpinLock that does not track ownership/threadIDs
SpinLock sl = new SpinLock(false);
// Used to synchronize with the Task below
ManualResetEventSlim mres = new ManualResetEventSlim(false);
// We will verify that the Task below runs on a separate thread
Console.WriteLine("main thread id = {0}", Thread.CurrentThread.ManagedThreadId);
// Now enter the SpinLock. Ordinarily, you would not want to spend so
// much time holding a SpinLock, but we do it here for the purpose of
// demonstrating that a non-ownership-tracking SpinLock can be exited
// by a different thread than that which was used to enter it.
bool lockTaken = false;
sl.Enter(ref lockTaken);
// Create a separate Task from which to Exit() the SpinLock
Task worker = Task.Factory.StartNew(() =>
{
Console.WriteLine("worker task thread id = {0} (should be different than main thread id)",
Thread.CurrentThread.ManagedThreadId);
// Now exit the SpinLock
try
{
sl.Exit();
Console.WriteLine("worker task: successfully exited SpinLock, as expected");
}
catch (Exception e)
{
Console.WriteLine("worker task: unexpected failure in exiting SpinLock: {0}", e.Message);
}
// Notify main thread to continue
mres.Set();
});
// Do this instead of worker.Wait(), because worker.Wait() could inline the worker Task,
// causing it to be run on the same thread. The purpose of this example is to show that
// a different thread can exit the SpinLock created (without thread tracking) on your thread.
mres.Wait();
// now Wait() on worker and clean up
worker.Wait();
mres.Dispose();
}
}
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Module SpinLockDemo
' Demonstrates:
' Default SpinLock construction ()
' SpinLock.Enter(ref bool)
' SpinLock.Exit()
Private Sub SpinLockSample1()
Dim sl As New SpinLock()
Dim sb As New StringBuilder()
' Action taken by each parallel job.
' Append to the StringBuilder 10000 times, protecting
' access to sb with a SpinLock.
Dim action As Action =
Sub()
Dim gotLock As Boolean = False
For i As Integer = 0 To 9999
gotLock = False
Try
sl.Enter(gotLock)
sb.Append((i Mod 10).ToString())
Finally
' Only give up the lock if you actually acquired it
If gotLock Then
sl.[Exit]()
End If
End Try
Next
End Sub
' Invoke 3 concurrent instances of the action above
Parallel.Invoke(action, action, action)
' Check/Show the results
Console.WriteLine("sb.Length = {0} (should be 30000)", sb.Length)
Console.WriteLine("number of occurrences of '5' in sb: {0} (should be 3000)", sb.ToString().Where(Function(c) (c = "5"c)).Count())
End Sub
' Demonstrates:
' Default SpinLock constructor (tracking thread owner)
' SpinLock.Enter(ref bool)
' SpinLock.Exit() throwing exception
' SpinLock.IsHeld
' SpinLock.IsHeldByCurrentThread
' SpinLock.IsThreadOwnerTrackingEnabled
Private Sub SpinLockSample2()
' Instantiate a SpinLock
Dim sl As New SpinLock()
' These MRESs help to sequence the two jobs below
Dim mre1 As New ManualResetEventSlim(False)
Dim mre2 As New ManualResetEventSlim(False)
Dim lockTaken As Boolean = False
Dim taskA As Task = Task.Factory.StartNew(
Sub()
Try
sl.Enter(lockTaken)
Console.WriteLine("Task A: entered SpinLock")
mre1.[Set]()
' Signal Task B to commence with its logic
' Wait for Task B to complete its logic
' (Normally, you would not want to perform such a potentially
' heavyweight operation while holding a SpinLock, but we do it
' here to more effectively show off SpinLock properties in
' taskB.)
mre2.Wait()
Finally
If lockTaken Then
sl.[Exit]()
End If
End Try
End Sub)
Dim taskB As Task = Task.Factory.StartNew(
Sub()
mre1.Wait()
' wait for Task A to signal me
Console.WriteLine("Task B: sl.IsHeld = {0} (should be true)", sl.IsHeld)
Console.WriteLine("Task B: sl.IsHeldByCurrentThread = {0} (should be false)", sl.IsHeldByCurrentThread)
Console.WriteLine("Task B: sl.IsThreadOwnerTrackingEnabled = {0} (should be true)", sl.IsThreadOwnerTrackingEnabled)
Try
sl.[Exit]()
Console.WriteLine("Task B: Released sl, should not have been able to!")
Catch e As Exception
Console.WriteLine("Task B: sl.Exit resulted in exception, as expected: {0}", e.Message)
End Try
' Signal Task A to exit the SpinLock
mre2.[Set]()
End Sub)
' Wait for task completion and clean up
Task.WaitAll(taskA, taskB)
mre1.Dispose()
mre2.Dispose()
End Sub
' Demonstrates:
' SpinLock constructor(false) -- thread ownership not tracked
Private Sub SpinLockSample3()
' Create SpinLock that does not track ownership/threadIDs
Dim sl As New SpinLock(False)
' Used to synchronize with the Task below
Dim mres As New ManualResetEventSlim(False)
' We will verify that the Task below runs on a separate thread
Console.WriteLine("main thread id = {0}", Thread.CurrentThread.ManagedThreadId)
' Now enter the SpinLock. Ordinarily, you would not want to spend so
' much time holding a SpinLock, but we do it here for the purpose of
' demonstrating that a non-ownership-tracking SpinLock can be exited
' by a different thread than that which was used to enter it.
Dim lockTaken As Boolean = False
sl.Enter(lockTaken)
' Create a separate Task
Dim worker As Task = Task.Factory.StartNew(
Sub()
Console.WriteLine("worker task thread id = {0} (should be different than main thread id)", Thread.CurrentThread.ManagedThreadId)
' Now exit the SpinLock
Try
sl.[Exit]()
Console.WriteLine("worker task: successfully exited SpinLock, as expected")
Catch e As Exception
Console.WriteLine("worker task: unexpected failure in exiting SpinLock: {0}", e.Message)
End Try
' Notify main thread to continue
mres.[Set]()
End Sub)
' Do this instead of worker.Wait(), because worker.Wait() could inline the worker Task,
' causing it to be run on the same thread. The purpose of this example is to show that
' a different thread can exit the SpinLock created (without thread tracking) on your thread.
mres.Wait()
' now Wait() on worker and clean up
worker.Wait()
mres.Dispose()
End Sub
End Module
Megjegyzések
A Spin Lock használatára példa : Útmutató: A SpinLock használata Low-Level szinkronizáláshoz.
A pörgetőzárak levélszintű zárakhoz használhatók, ahol az objektumfoglalás Monitoregy méretben vagy a szemétgyűjtési nyomás miatt túl költséges. A pörgetési zár hasznos lehet a blokkolás elkerülése érdekében; azonban, ha jelentős mennyiségű blokkolásra számít, akkor valószínűleg nem érdemes pörgetőzárakat használni a túlzott fonás miatt. A fonás akkor lehet hasznos, ha a zárolások részletesek és nagyok (például csomópontonkénti zárolás egy csatolt listában), és akkor is, ha a zárolási időtartamok mindig rendkívül rövidek. Általánosságban elmondható, hogy a pörgetési zár megtartása során kerülni kell az alábbi műveletek egyikét:
Blokkoló
bármit meghívhat, ami blokkolhat,
egyszerre több pörgetési zárat kell tartania,
dinamikusan küldött hívások (interfészek és virtuális gépek) indítása,
statikusan küldött hívásokat kezdeményezhet bármely olyan kódba, amely nem rendelkezik saját kóddal, vagy
memória kiosztása.
SpinLock csak azt követően szabad használni, hogy ön megállapította, hogy ez javítja az alkalmazás teljesítményét. Azt is fontos megjegyezni, hogy SpinLock teljesítménybeli okokból értéktípus. Ezért nagyon óvatosnak kell lennie, hogy ne másoljon véletlenül egy példányt SpinLock , mivel a két példány (az eredeti és a másolat) ezután teljesen függetlenné válna egymástól, ami valószínűleg az alkalmazás hibás viselkedéséhez vezetne. Ha egy példányt SpinLock át kell adni, azt nem érték, hanem hivatkozás útján kell átadni.
Ne tárolja SpinLock a példányokat írásvédett mezőkben.
Konstruktorok
| Name | Description |
|---|---|
| SpinLock(Boolean) |
Inicializálja a SpinLock struktúra új példányát a szálazonosítók nyomon követésének lehetőségével a hibakeresés javítása érdekében. |
Tulajdonságok
| Name | Description |
|---|---|
| IsHeld |
Lekérdezi, hogy a zárolást jelenleg bármilyen szál tartja-e. |
| IsHeldByCurrentThread |
Lekérdezi, hogy az aktuális szál tartja-e a zárolást. |
| IsThreadOwnerTrackingEnabled |
Lekérdezi, hogy engedélyezve van-e a szál tulajdonjogának nyomon követése ehhez a példányhoz. |
Metódusok
| Name | Description |
|---|---|
| Enter(Boolean) |
A zárolást megbízható módon szerzi be, így még ha kivétel is történik a metódushíváson belül, megbízhatóan vizsgálható annak megállapításához, |
| Exit() |
Feloldja a zárolást. |
| Exit(Boolean) |
Feloldja a zárolást. |
| TryEnter(Boolean) |
A zárolás megbízható módon történő beszerzésére tett kísérletek, amelyek akkor is megbízhatóan vizsgálhatók, ha kivétel történik a metódushíváson belül, annak megállapításához, |
| TryEnter(Int32, Boolean) |
A zárolás megbízható módon történő beszerzésére tett kísérletek, amelyek akkor is megbízhatóan vizsgálhatók, ha kivétel történik a metódushíváson belül, annak megállapításához, |
| TryEnter(TimeSpan, Boolean) |
A zárolás megbízható módon történő beszerzésére tett kísérletek, amelyek akkor is megbízhatóan vizsgálhatók, ha kivétel történik a metódushíváson belül, annak megállapításához, |
A következőre érvényes:
Szálbiztonság
A tagok SpinLock mindegyike szálbiztos, és egyidejűleg több szálból is használható.