Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, bu API'nin başvuru belgelerine ek açıklamalar sağlar.
Monitor sınıfı, , Monitor.Enterve Monitor.TryEnter yöntemlerini çağırarak belirli bir nesne üzerinde kilit alıp serbest bırakarak kodun Monitor.Exitbir bölgesine erişimi eşitlemenize olanak tanır. Nesne kilitleri, genellikle kritik bölüm olarak adlandırılan bir kod bloğuna erişimi kısıtlama olanağı sağlar. Bir iş parçacığı bir nesnenin kilidine sahip olsa da, başka hiçbir iş parçacığı bu kilidi edinemez. Sınıfını Monitor , diğer iş parçacığı kodu farklı bir kilitli nesne kullanarak yürütmediği sürece kilit sahibi tarafından yürütülen uygulama kodunun bir bölümüne başka bir iş parçacığının erişmesine izin verilmediğinden emin olmak için de kullanabilirsiniz. Monitor sınıfı iş parçacığı bağımlılığına sahip olduğundan, kilidi edinen iş parçacığının Monitor.Exit yöntemini çağırarak kilidi serbest bırakması gerekir.
Genel Bakış
Monitor aşağıdaki özelliklere sahiptir:
- İsteğe bağlı bir nesneyle ilişkilendirilir.
- İlişkisizdir, yani doğrudan herhangi bir bağlamdan çağrılabilir.
- Sınıfın Monitor bir örneği oluşturulamaz; sınıfın yöntemlerinin Monitor tümü statiktir. Her yöntem, kritik bölüme erişimi denetleyen eşitlenmiş nesneye geçirilir.
Uyarı
Monitor sınıfını, String dizeleri değil de diğer başvuru türlerini (değer türleri değil) kilitlemek için kullanın. Ayrıntılar için, bu makalenin devamında Enter yönteminin aşırı yüklemelerine ve kilitleme nesnesi bölümüne bakın.
Aşağıdaki tabloda, eşitlenmiş nesnelere erişen iş parçacıkları tarafından gerçekleştirilebilecek eylemler açıklanmaktadır:
| Eylem | Açıklama |
|---|---|
| Enter, TryEnter | Bir nesne için kilit alır. Bu eylem, kritik bir bölümün başlangıcını da işaretler. Kritik bölümdeki yönergeleri farklı bir kilitli nesne kullanarak yürütmediği sürece başka hiçbir iş parçacığı kritik bölüme giremez. |
| Wait | Diğer iş parçacıklarının nesneyi kilitleyebilmesi ve erişebilmesi için nesne üzerindeki kilidi serbest bırakır. Başka bir iş parçacığı nesneye erişirken çağıran iş parçacığı bekler. Nesnenin durumundaki değişiklikler hakkında bekleyen iş parçacıklarını bilgilendirmek için darbesel sinyaller kullanılır. |
| Pulse (sinyal), PulseAll | Bir veya daha fazla bekleyen iş parçacığına sinyal gönderir. Sinyal, kilitli nesnenin durumunun değiştiğini ve kilidin sahibinin kilidi serbest bırakmaya hazır olduğunu bekleyen iş parçacığını bildirir. Bekleyen iş parçacığı nihayet nesnenin kilidini alabilmesi için nesnenin hazır kuyruğuna yerleştirilir. İş parçacığı kilidine sahip olduktan sonra, gerekli duruma ulaşılıp ulaşılamadığını görmek için nesnenin yeni durumunu denetleyebilir. |
| Exit | Bir nesne üzerindeki kilidi serbest bırakır. Bu eylem, kilitli nesne tarafından korunan kritik bir bölümün sonunu da işaretler. |
Enter ve TryEnter yöntemleri için iki aşırı yükleme kümesi vardır. Bir aşırı yükleme kümesi, kilit alınırken bir özel durum oluştuğunda bile atomik olarak ayarlanmış bir ref (C#'de) veya ByRef (Visual Basic'te) Boolean parametresine true sahiptir. Kilidin koruduğu kaynaklar tutarlı bir durumda olmasa bile kilidin her durumda serbest bırakılması kritikse bu aşırı yüklemeleri kullanın.
Kilit nesnesi
İzleyici sınıfı, kritik bölüme erişimi denetleyen bir nesne üzerinde çalışan (static Visual Basic'te) yöntemlerden oluşur Shared . Eşitlenen her nesne için aşağıdaki bilgiler korunur:
- Kilidi şu anda tutan iş parçacığına referans.
- Kilit almaya hazır iş parçacıklarının bulunduğu hazır kuyruğa bir referans.
- Kilitli nesnenin durumu değiştiğinde bildirim bekleyen iş parçacıklarını içeren bir bekleme kuyruğuna referans.
Monitor nesneleri (başvuru türleri) kilitler, değer türlerini kilitlemez. Bir değer türünü Enter ve Exit öğesine geçirebilirsiniz, ancak her çağrı için ayrı olarak kutulanır. Her çağrı ayrı bir nesne oluşturduğundan, Enter hiçbir zaman engellemez ve koruduğu varsayılan kod gerçekten eşitlenmez. Buna ek olarak, geçirilen Exit nesne, geçirilen Enternesneden farklıdır, bu nedenle Monitor "Nesne eşitleme yöntemi zaman uyumsuz bir kod bloğundan çağrıldı" iletisiyle özel durum oluşturur SynchronizationLockException .
Aşağıdaki örnekte bu sorun gösterilmektedir. O, her biri 250 milisaniye boyunca uyuyan on görevi başlatır. Ardından her görev, nTasksgerçekten başlatılan ve yürütülen görev sayısını saymaya yönelik bir sayaç değişkenini güncelleştirir.
nTasks Birden çok görev tarafından aynı anda güncelleştirilebilen genel bir değişken olduğundan, birden çok görev tarafından aynı anda değiştirilmesini korumak için bir izleyici kullanılır. Ancak, örnekteki çıktıda gösterildiği gibi, görevlerin her biri bir SynchronizationLockException özel durum oluşturur.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example1
{
public static void Main()
{
int nTasks = 0;
List<Task> tasks = new List<Task>();
try
{
for (int ctr = 0; ctr < 10; ctr++)
tasks.Add(Task.Run(() =>
{ // Instead of doing some work, just sleep.
Thread.Sleep(250);
// Increment the number of tasks.
Monitor.Enter(nTasks);
try
{
nTasks += 1;
}
finally
{
Monitor.Exit(nTasks);
}
}));
Task.WaitAll(tasks.ToArray());
Console.WriteLine($"{nTasks} tasks started and executed.");
}
catch (AggregateException e)
{
String msg = String.Empty;
foreach (var ie in e.InnerExceptions)
{
Console.WriteLine($"{ie.GetType().Name}");
if (!msg.Contains(ie.Message))
msg += ie.Message + Environment.NewLine;
}
Console.WriteLine("\nException Message(s):");
Console.WriteLine(msg);
}
}
}
// The example displays the following output:
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
// SynchronizationLockException
//
// Exception Message(s):
// Object synchronization method was called from an unsynchronized block of code.
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks
Module Example3
Public Sub Main()
Dim nTasks As Integer = 0
Dim tasks As New List(Of Task)()
Try
For ctr As Integer = 0 To 9
tasks.Add(Task.Run(Sub()
' Instead of doing some work, just sleep.
Thread.Sleep(250)
' Increment the number of tasks.
Monitor.Enter(nTasks)
Try
nTasks += 1
Finally
Monitor.Exit(nTasks)
End Try
End Sub))
Next
Task.WaitAll(tasks.ToArray())
Console.WriteLine("{0} tasks started and executed.", nTasks)
Catch e As AggregateException
Dim msg As String = String.Empty
For Each ie In e.InnerExceptions
Console.WriteLine("{0}", ie.GetType().Name)
If Not msg.Contains(ie.Message) Then
msg += ie.Message + Environment.NewLine
End If
Next
Console.WriteLine(vbCrLf + "Exception Message(s):")
Console.WriteLine(msg)
End Try
End Sub
End Module
' The example displays the following output:
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
' SynchronizationLockException
'
' Exception Message(s):
' Object synchronization method was called from an unsynchronized block of code.
Her görev, SynchronizationLockException yöntemine yapılan çağrıdan önce nTasks değişkeni kutulandığı için bir Monitor.Enter özel durum fırlatır. Başka bir deyişle, her yöntem çağrısına diğerlerinden bağımsız olan ayrı bir değişken atanır.
nTasks yöntemine yapılan çağrıda Monitor.Exit yeniden kutulanır. Bir kez daha bu, birbirinden bağımsız on yeni kutulanmış değişken nTasks ve Monitor.Enter yöntemini çağırmada oluşturulan on kutulanmış değişken oluşturur. İstisna oluşturulur çünkü kodumuz, daha önce kilitlenmemiş yeni oluşturulan bir değişkenin kilidini çözmeye çalışıyor.
Aşağıdaki örnekte gösterildiği gibi, Enter ve Exit çağrılmadan önce bir değer türü değişkenini kutulayıp, aynı kutulanmış nesneyi her iki yönteme de geçirebilirsiniz, ancak bunu yapmanın bir avantajı yoktur. Kutulanmamış değişkendeki değişiklikler kutulanmış kopyaya yansıtılmaz ve kutulanmış kopyanın değerini değiştirmenin hiçbir yolu yoktur.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
int nTasks = 0;
object o = nTasks;
List<Task> tasks = new List<Task>();
try {
for (int ctr = 0; ctr < 10; ctr++)
tasks.Add(Task.Run( () => { // Instead of doing some work, just sleep.
Thread.Sleep(250);
// Increment the number of tasks.
Monitor.Enter(o);
try {
nTasks++;
}
finally {
Monitor.Exit(o);
}
} ));
Task.WaitAll(tasks.ToArray());
Console.WriteLine($"{nTasks} tasks started and executed.");
}
catch (AggregateException e) {
String msg = String.Empty;
foreach (var ie in e.InnerExceptions) {
Console.WriteLine($"{ie.GetType().Name}");
if (! msg.Contains(ie.Message))
msg += ie.Message + Environment.NewLine;
}
Console.WriteLine("\nException Message(s):");
Console.WriteLine(msg);
}
}
}
// The example displays the following output:
// 10 tasks started and executed.
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks
Module Example2
Public Sub Main()
Dim nTasks As Integer = 0
Dim o As Object = nTasks
Dim tasks As New List(Of Task)()
Try
For ctr As Integer = 0 To 9
tasks.Add(Task.Run(Sub()
' Instead of doing some work, just sleep.
Thread.Sleep(250)
' Increment the number of tasks.
Monitor.Enter(o)
Try
nTasks += 1
Finally
Monitor.Exit(o)
End Try
End Sub))
Next
Task.WaitAll(tasks.ToArray())
Console.WriteLine("{0} tasks started and executed.", nTasks)
Catch e As AggregateException
Dim msg As String = String.Empty
For Each ie In e.InnerExceptions
Console.WriteLine("{0}", ie.GetType().Name)
If Not msg.Contains(ie.Message) Then
msg += ie.Message + Environment.NewLine
End If
Next
Console.WriteLine(vbCrLf + "Exception Message(s):")
Console.WriteLine(msg)
End Try
End Sub
End Module
' The example displays the following output:
' 10 tasks started and executed.
Eşitlemek için bir nesne seçerken, yalnızca özel veya dahili nesnelere odaklanmalısınız. Dış nesneler üzerinde kilitleme yapmak, ilgisiz kodlar farklı amaçlar için aynı nesneleri kilitlemeye karar verebileceğinden, kilitlenmelere neden olabilir.
Kilit için kullanılan nesne MarshalByRefObject türetilmişse, birden fazla uygulama etki alanında bulunan bir nesne üzerinde senkronizasyon yapabileceğinizi unutmayın.
Kritik bölüm
Kritik bir bölümün başlangıcını ve sonunu işaretlemek için Enter ve Exit yöntemlerini kullanın.
Uyarı
Enter ve Exit yöntemleri tarafından sağlanan işlevsellik, C# içindeki lock deyimi ve Visual Basic'teki SyncLock deyimi ile sağlanan işleve aynıdır, ancak dil yapıları Monitor.Enter(Object, Boolean) yöntemi aşırı yüklemesini ve Monitor.Exit yöntemini bir try...
finally bloğunu monitörün serbest bırakıldığını garanti etmek için kullanın.
Eğer kritik bölüm bitişik yönergeler kümesiyse, Enter yöntemi tarafından alınan kilit, kapalı kodun kilitli nesneyle yalnızca tek bir iş parçacığı tarafından çalıştırılabileceğini garanti eder. Bu durumda, bu kodu bir try bloğa yerleştirmenizi ve yöntemine çağrıyı Exit bir finally blokta yerleştirmenizi öneririz. Bu, bir özel durum oluştuğunda bile kilidin serbest bırakılmasını sağlar. Aşağıdaki kod parçası bu düzeni gösterir.
// Define the lock object.
var obj = new Object();
// Define the critical section.
Monitor.Enter(obj);
try
{
// Code to execute one thread at a time.
}
// catch blocks go here.
finally
{
Monitor.Exit(obj);
}
' Define the lock object.
Dim obj As New Object()
' Define the critical section.
Monitor.Enter(obj)
Try
' Code to execute one thread at a time.
' catch blocks go here.
Finally
Monitor.Exit(obj)
End Try
Bu tesis genellikle bir sınıfın statik veya örnek yöntemine erişimi eşitlemek için kullanılır.
Kritik bir bölüm, bir metotun tümünü kapsıyorsa, kilitleme işlevi, System.Runtime.CompilerServices.MethodImplAttribute metot üzerine yerleştirilerek ve Synchronized oluşturucusunda System.Runtime.CompilerServices.MethodImplAttribute değeri belirtilerek gerçekleştirilebilir. Bu özniteliği kullandığınızda Enter ve Exit metot çağrıları gerekli değildir. Aşağıdaki kod parçası bu düzeni gösterir:
[MethodImplAttribute(MethodImplOptions.Synchronized)]
void MethodToLock()
{
// Method implementation.
}
<MethodImplAttribute(MethodImplOptions.Synchronized)>
Sub MethodToLock()
' Method implementation.
End Sub
Unutmayın ki, bu öznitelik, geçerli iş parçacığının yöntem dönene kadar kilidi elinde tutmasına neden olur. Ancak, kilidi daha erken serbest bırakma imkânı varsa, bu öznitelik yerine metodun içinde Monitor sınıfını, ya da C# lock deyimini veya Visual Basic SyncLock deyimini kullanabilirsiniz.
Enter ve Exit deyimlerinin, belirli bir nesneyi kilitleyip serbest bırakırken üye veya sınıf sınırlarını ya da her ikisini birden aşması mümkün olsa da, bu uygulama önerilmez.
Pulse, PulseAll ve Wait
Bir iş parçacığı kilidin sahibi olduktan ve kilidin koruduğu kritik bölüme girdikten sonra, Monitor.Wait, Monitor.Pulse ve Monitor.PulseAll yöntemlerini çağırabilir.
Kilidi tutan iş parçacığı çağırdığında Wait, kilit serbest bırakılır ve iş parçacığı eşitlenen nesnenin bekleme kuyruğuna eklenir. Eğer varsa, hazır kuyruktaki ilk iş parçacığı kilidi alır ve kritik bölüme girer. Wait iş parçacığı, kilidi elinde bulunduran iş parçacığı Monitor.Pulse veya Monitor.PulseAll yöntemini çağırdığında bekleme kuyruğundan hazır kuyruğa taşınır (taşınabilmesi için, iş parçacığının bekleme kuyruğunun başında olması gerekir). çağıran Wait iş parçacığı kilidi yeniden alırsa yöntemi döndürür.
Kilidi tutan iş parçacığı Pulse'ı çağırdığında, bekleme kuyruğunun başındaki iş parçacığı, hazır kuyruğa taşınır. PulseAll yöntemine yapılan çağrı, tüm iş parçacıklarını bekleyen kuyruktan hazır kuyruğa taşır.
İzleyiciler ve bekleme tutamaçları
Nesne kullanımı Monitor ile sınıf kullanımı WaitHandle arasındaki ayrımı not etmek önemlidir.
- Sınıfı Monitor tamamen yönetilir, tamamen taşınabilir ve işletim sistemi kaynak gereksinimleri açısından daha verimli olabilir.
- WaitHandle nesneler işletim sistemi tarafından beklenebilen nesneleri temsil eder, yönetilen ve yönetilmeyen kod arasında eşitleme yapmak için yararlıdır ve aynı anda birçok nesnede bekleme yeteneği gibi bazı gelişmiş işletim sistemi özelliklerini kullanıma sunar.
Örnekler
Aşağıdaki örnek, Monitor sınıfını kullanarak Random sınıfı tarafından temsil edilen bir rastgele sayı üreteci örneğine erişimi eşitler. Örnek, her biri bir iş parçacığı havuzunda eş zamanlı olmayan şekilde yürütülen on görev oluşturur. Her görev 10.000 rastgele sayı oluşturur, bunların ortalamasını hesaplar ve oluşturulan rastgele sayı sayısının ve toplamlarının çalışan toplamını koruyan iki yordam düzeyinde değişkeni güncelleştirir. Tüm görevler yürütüldükten sonra, bu iki değer genel ortalamayı hesaplamak için kullanılır.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example2
{
public static void Main()
{
List<Task> tasks = new List<Task>();
Random rnd = new Random();
long total = 0;
int n = 0;
for (int taskCtr = 0; taskCtr < 10; taskCtr++)
tasks.Add(Task.Run(() =>
{
int[] values = new int[10000];
int taskTotal = 0;
int taskN = 0;
int ctr = 0;
Monitor.Enter(rnd);
// Generate 10,000 random integers
for (ctr = 0; ctr < 10000; ctr++)
values[ctr] = rnd.Next(0, 1001);
Monitor.Exit(rnd);
taskN = ctr;
foreach (var value in values)
taskTotal += value;
Console.WriteLine("Mean for task {0,2}: {1:N2} (N={2:N0})",
Task.CurrentId, (taskTotal * 1.0) / taskN,
taskN);
Interlocked.Add(ref n, taskN);
Interlocked.Add(ref total, taskTotal);
}));
try
{
Task.WaitAll(tasks.ToArray());
Console.WriteLine($"\nMean for all tasks: {(total * 1.0) / n:N2} (N={n:N0})");
}
catch (AggregateException e)
{
foreach (var ie in e.InnerExceptions)
Console.WriteLine($"{ie.GetType().Name}: {ie.Message}");
}
}
}
// The example displays output like the following:
// Mean for task 1: 499.04 (N=10,000)
// Mean for task 2: 500.42 (N=10,000)
// Mean for task 3: 499.65 (N=10,000)
// Mean for task 8: 502.59 (N=10,000)
// Mean for task 5: 502.75 (N=10,000)
// Mean for task 4: 494.88 (N=10,000)
// Mean for task 7: 499.22 (N=10,000)
// Mean for task 10: 496.45 (N=10,000)
// Mean for task 6: 499.75 (N=10,000)
// Mean for task 9: 502.79 (N=10,000)
//
// Mean for all tasks: 499.75 (N=100,000)
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks
Module Example4
Public Sub Main()
Dim tasks As New List(Of Task)()
Dim rnd As New Random()
Dim total As Long = 0
Dim n As Integer = 0
For taskCtr As Integer = 0 To 9
tasks.Add(Task.Run(Sub()
Dim values(9999) As Integer
Dim taskTotal As Integer = 0
Dim taskN As Integer = 0
Dim ctr As Integer = 0
Monitor.Enter(rnd)
' Generate 10,000 random integers.
For ctr = 0 To 9999
values(ctr) = rnd.Next(0, 1001)
Next
Monitor.Exit(rnd)
taskN = ctr
For Each value In values
taskTotal += value
Next
Console.WriteLine("Mean for task {0,2}: {1:N2} (N={2:N0})",
Task.CurrentId, taskTotal / taskN,
taskN)
Interlocked.Add(n, taskN)
Interlocked.Add(total, taskTotal)
End Sub))
Next
Try
Task.WaitAll(tasks.ToArray())
Console.WriteLine()
Console.WriteLine("Mean for all tasks: {0:N2} (N={1:N0})",
(total * 1.0) / n, n)
Catch e As AggregateException
For Each ie In e.InnerExceptions
Console.WriteLine("{0}: {1}", ie.GetType().Name, ie.Message)
Next
End Try
End Sub
End Module
' The example displays output like the following:
' Mean for task 1: 499.04 (N=10,000)
' Mean for task 2: 500.42 (N=10,000)
' Mean for task 3: 499.65 (N=10,000)
' Mean for task 8: 502.59 (N=10,000)
' Mean for task 5: 502.75 (N=10,000)
' Mean for task 4: 494.88 (N=10,000)
' Mean for task 7: 499.22 (N=10,000)
' Mean for task 10: 496.45 (N=10,000)
' Mean for task 6: 499.75 (N=10,000)
' Mean for task 9: 502.79 (N=10,000)
'
' Mean for all tasks: 499.75 (N=100,000)
İş parçacığı havuzu iş parçacığında çalışan herhangi bir görevden erişilebildiği için, total ve n değişkenlerine erişim de senkronize edilmelidir.
Interlocked.Add yöntemi bu amaç için kullanılır.
Aşağıdaki örnek, Monitor veya lock dil yapısıyla uygulanmış olan SyncLock sınıfının, Interlocked sınıfının ve AutoResetEvent sınıfının birleştirilmiş kullanımını göstermektedir. Bir kaynağa sırasıyla eşitlenmiş ve eşitlenmemiş erişim sağlayan iki sınıf, internal ve Friend'ü SyncResource (C#'de) veya UnSyncResource (Visual Basic'te) tanımlar. Örnekte eşitlenmiş ve eşitlenmemiş erişim arasındaki farkın gösterildiğinden emin olmak için (her yöntem çağrısı hızla tamamlanırsa bu durum söz konusu olabilir), yöntem rastgele bir gecikme içerir: özelliği eşit olan Thread.ManagedThreadId iş parçacıkları için yöntem, 2.000 milisaniyelik bir gecikmeye neden olmaya çağırır Thread.Sleep . Dikkat edin ki, SyncResource sınıfı genel olmadığından, istemci kodunun hiçbiri senkronize kaynak üzerinde kilit almaz; iç sınıfın kendisi kilidi alır. Bu, kötü amaçlı kodun ortak bir nesneye kilitlenmesini önler.
using System;
using System.Threading;
internal class SyncResource
{
// Use a monitor to enforce synchronization.
public void Access()
{
lock(this) {
Console.WriteLine($"Starting synchronized resource access on thread #{Thread.CurrentThread.ManagedThreadId}");
if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
Thread.Sleep(2000);
Thread.Sleep(200);
Console.WriteLine($"Stopping synchronized resource access on thread #{Thread.CurrentThread.ManagedThreadId}");
}
}
}
internal class UnSyncResource
{
// Do not enforce synchronization.
public void Access()
{
Console.WriteLine($"Starting unsynchronized resource access on Thread #{Thread.CurrentThread.ManagedThreadId}");
if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
Thread.Sleep(2000);
Thread.Sleep(200);
Console.WriteLine($"Stopping unsynchronized resource access on thread #{Thread.CurrentThread.ManagedThreadId}");
}
}
public class App
{
private static int numOps;
private static AutoResetEvent opsAreDone = new AutoResetEvent(false);
private static SyncResource SyncRes = new SyncResource();
private static UnSyncResource UnSyncRes = new UnSyncResource();
public static void Main()
{
// Set the number of synchronized calls.
numOps = 5;
for (int ctr = 0; ctr <= 4; ctr++)
ThreadPool.QueueUserWorkItem(new WaitCallback(SyncUpdateResource));
// Wait until this WaitHandle is signaled.
opsAreDone.WaitOne();
Console.WriteLine("\t\nAll synchronized operations have completed.\n");
// Reset the count for unsynchronized calls.
numOps = 5;
for (int ctr = 0; ctr <= 4; ctr++)
ThreadPool.QueueUserWorkItem(new WaitCallback(UnSyncUpdateResource));
// Wait until this WaitHandle is signaled.
opsAreDone.WaitOne();
Console.WriteLine("\t\nAll unsynchronized thread operations have completed.\n");
}
static void SyncUpdateResource(Object state)
{
// Call the internal synchronized method.
SyncRes.Access();
// Ensure that only one thread can decrement the counter at a time.
if (Interlocked.Decrement(ref numOps) == 0)
// Announce to Main that in fact all thread calls are done.
opsAreDone.Set();
}
static void UnSyncUpdateResource(Object state)
{
// Call the unsynchronized method.
UnSyncRes.Access();
// Ensure that only one thread can decrement the counter at a time.
if (Interlocked.Decrement(ref numOps) == 0)
// Announce to Main that in fact all thread calls are done.
opsAreDone.Set();
}
}
// The example displays output like the following:
// Starting synchronized resource access on thread #6
// Stopping synchronized resource access on thread #6
// Starting synchronized resource access on thread #7
// Stopping synchronized resource access on thread #7
// Starting synchronized resource access on thread #3
// Stopping synchronized resource access on thread #3
// Starting synchronized resource access on thread #4
// Stopping synchronized resource access on thread #4
// Starting synchronized resource access on thread #5
// Stopping synchronized resource access on thread #5
//
// All synchronized operations have completed.
//
// Starting unsynchronized resource access on Thread #7
// Starting unsynchronized resource access on Thread #9
// Starting unsynchronized resource access on Thread #10
// Starting unsynchronized resource access on Thread #6
// Starting unsynchronized resource access on Thread #3
// Stopping unsynchronized resource access on thread #7
// Stopping unsynchronized resource access on thread #9
// Stopping unsynchronized resource access on thread #3
// Stopping unsynchronized resource access on thread #10
// Stopping unsynchronized resource access on thread #6
//
// All unsynchronized thread operations have completed.
Imports System.Threading
Friend Class SyncResource
' Use a monitor to enforce synchronization.
Public Sub Access()
SyncLock Me
Console.WriteLine("Starting synchronized resource access on thread #{0}",
Thread.CurrentThread.ManagedThreadId)
If Thread.CurrentThread.ManagedThreadId Mod 2 = 0 Then
Thread.Sleep(2000)
End If
Thread.Sleep(200)
Console.WriteLine("Stopping synchronized resource access on thread #{0}",
Thread.CurrentThread.ManagedThreadId)
End SyncLock
End Sub
End Class
Friend Class UnSyncResource
' Do not enforce synchronization.
Public Sub Access()
Console.WriteLine("Starting unsynchronized resource access on Thread #{0}",
Thread.CurrentThread.ManagedThreadId)
If Thread.CurrentThread.ManagedThreadId Mod 2 = 0 Then
Thread.Sleep(2000)
End If
Thread.Sleep(200)
Console.WriteLine("Stopping unsynchronized resource access on thread #{0}",
Thread.CurrentThread.ManagedThreadId)
End Sub
End Class
Public Module App
Private numOps As Integer
Private opsAreDone As New AutoResetEvent(False)
Private SyncRes As New SyncResource()
Private UnSyncRes As New UnSyncResource()
Public Sub Main()
' Set the number of synchronized calls.
numOps = 5
For ctr As Integer = 0 To 4
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SyncUpdateResource))
Next
' Wait until this WaitHandle is signaled.
opsAreDone.WaitOne()
Console.WriteLine(vbTab + Environment.NewLine + "All synchronized operations have completed.")
Console.WriteLine()
numOps = 5
' Reset the count for unsynchronized calls.
For ctr As Integer = 0 To 4
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf UnSyncUpdateResource))
Next
' Wait until this WaitHandle is signaled.
opsAreDone.WaitOne()
Console.WriteLine(vbTab + Environment.NewLine + "All unsynchronized thread operations have completed.")
End Sub
Sub SyncUpdateResource()
' Call the internal synchronized method.
SyncRes.Access()
' Ensure that only one thread can decrement the counter at a time.
If Interlocked.Decrement(numOps) = 0 Then
' Announce to Main that in fact all thread calls are done.
opsAreDone.Set()
End If
End Sub
Sub UnSyncUpdateResource()
' Call the unsynchronized method.
UnSyncRes.Access()
' Ensure that only one thread can decrement the counter at a time.
If Interlocked.Decrement(numOps) = 0 Then
' Announce to Main that in fact all thread calls are done.
opsAreDone.Set()
End If
End Sub
End Module
' The example displays output like the following:
' Starting synchronized resource access on thread #6
' Stopping synchronized resource access on thread #6
' Starting synchronized resource access on thread #7
' Stopping synchronized resource access on thread #7
' Starting synchronized resource access on thread #3
' Stopping synchronized resource access on thread #3
' Starting synchronized resource access on thread #4
' Stopping synchronized resource access on thread #4
' Starting synchronized resource access on thread #5
' Stopping synchronized resource access on thread #5
'
' All synchronized operations have completed.
'
' Starting unsynchronized resource access on Thread #7
' Starting unsynchronized resource access on Thread #9
' Starting unsynchronized resource access on Thread #10
' Starting unsynchronized resource access on Thread #6
' Starting unsynchronized resource access on Thread #3
' Stopping unsynchronized resource access on thread #7
' Stopping unsynchronized resource access on thread #9
' Stopping unsynchronized resource access on thread #3
' Stopping unsynchronized resource access on thread #10
' Stopping unsynchronized resource access on thread #6
'
' All unsynchronized thread operations have completed.
Örnek, numOpskaynağa erişmeye çalışacak iş parçacığı sayısını tanımlayan bir değişkeni tanımlar. Uygulama iş parçacığı, ThreadPool.QueueUserWorkItem(WaitCallback) yöntemini eşitlenmiş ve eşitlenmemiş erişim için beşer kez çağırır.
ThreadPool.QueueUserWorkItem(WaitCallback) yöntemi, parametre kabul etmeyen ve değer döndürmeyen bir temsilci olmak üzere tek bir parametreye sahiptir. Eşitlenmiş erişim için yöntemini çağırır SyncUpdateResource ; eşitlenmemiş erişim için yöntemini çağırır UnSyncUpdateResource . Her yöntem kümesi çağrılarından sonra, uygulama iş parçacığı, AutoResetEvent.WaitOne yöntemini örnek sinyal verilene kadar engellemek için çağırır.
SyncUpdateResource yöntemine yapılan her çağrı, iç SyncResource.Access yöntemini çağırır ve ardından Interlocked.Decrement sayacını azaltmak için numOps yöntemini çağırır.
Interlocked.Decrement yöntemi sayacın azalmasını sağlamak için kullanılır, aksi takdirde ikinci bir iş parçacığının değere ilk iş parçacığının azalan değeri değişkende depolanmadan önce erişeceğinden emin olamazsınız. Son eşitlenen çalışan iş parçacığı sayacı sıfıra düşürdüğünde, bu, tüm eşitlenen iş parçacıklarının kaynağa erişimini tamamladıklarını gösterir, bu noktada SyncUpdateResource yöntemi, EventWaitHandle.Set yöntemini çağırarak ana iş parçacığına yürütmeye devam etmesi için sinyal gönderir.
UnSyncUpdateResource yöntemine yapılan her çağrı, iç UnSyncResource.Access yöntemini çağırır ve ardından Interlocked.Decrement sayacını azaltmak için numOps yöntemini çağırır. Bir kez daha, ilk iş parçacığının Interlocked.Decrement azalan değeri değişkenine atanmadan önce ikinci bir iş parçacığının değere erişmediğinden emin olmak için sayacı azaltma yöntemi kullanılır. Son eşitlenmemiş işçi iş parçacığı, sayacı sıfırladığında ve artık eşitlenmemiş iş parçacıklarının kaynağa erişmesi gerekmediğini gösterdiğinde, UnSyncUpdateResource yöntemini çağırır, bu da EventWaitHandle.Set yöntemi aracılığıyla ana iş parçacığının yürütmeye devam etmesi için sinyal gönderir.
Örnekteki çıktıda gösterildiği gibi, eşitlenmiş erişim çağıran iş parçacığının başka bir iş parçacığına erişmeden önce korumalı kaynaktan çıkmasını sağlar; her iş parçacığı öncülünü bekler. Öte yandan, kilit olmadan, UnSyncResource.Access yöntemi iş parçacıklarının onlara ulaştığı sırayla çağrılır.