System.Threading.Monitor sınıfı

Bu makale, bu API'nin başvuru belgelerine ek açıklamalar sağlar.

Monitor sınıfı, , Monitor.TryEnterve Monitor.Exit yöntemlerini çağırarak belirli bir nesne üzerinde kilit alıp serbest bırakarak kodun Monitor.Enterbir 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. İzleyici sınıfı iş parçacığı benzitesine sahip olduğundan, kilit alan 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.

Not

Monitor dizeleri (başka bir deyişle, dışındaki başvuru türleri), değer türleri Stringdışındaki nesneleri kilitlemek için sınıfını kullanın. Ayrıntılar için bu makalenin devamında yönteminin Enter aşırı yüklemeleri ve Nesne kilitleme 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 kilitlemesine ve nesneye erişmesine izin vermek için nesne üzerindeki kilidi serbest bırakır. Başka bir iş parçacığı nesneye erişirken çağıran iş parçacığı bekler. Darbe sinyalleri, bekleyen iş parçacıklarını nesnenin durumundaki değişiklikler hakkında bilgilendirmek için kullanılır.
Pulse (sinyal), PulseAll Bir veya daha fazla bekleyen iş parçacığına sinyal gönderir. Sinyal, bekleyen bir iş parçacığına kilitli nesnenin durumunun değiştiğini ve kilidin sahibinin kilidi serbest bırakmaya hazır olduğunu bildirir. Bekleyen iş parçacığı nesnenin hazır kuyruğuna yerleştirilir, böylece nesnenin kilidini alabilir. İş 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.

ve TryEnter yöntemleri için Enter 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.

Lock nesnesi

İzleyici sınıfı, kritik bölüme erişimi denetleyen bir nesne üzerinde çalışan (Shared Visual Basic'te) yöntemlerden oluşur static . Eşitlenen her nesne için aşağıdaki bilgiler korunur:

  • Şu anda kilidi tutan iş parçacığına başvuru.
  • Kilidi almaya hazır iş parçacıklarını içeren hazır kuyruğa başvuru.
  • Kilitli nesnenin durumundaki bir değişikliğin bildirimini bekleyen iş parçacıklarını içeren bir bekleme kuyruğu başvurusu.

Monitor nesneleri (başvuru türleri) kilitler, değer türlerini kilitlemez. ve Exitöğesine Enter bir değer türü 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. Her biri 250 milisaniye boyunca uyuyan on görev 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("{0} tasks started and executed.", nTasks);
        }
        catch (AggregateException e)
        {
            String msg = String.Empty;
            foreach (var ie in e.InnerExceptions)
            {
                Console.WriteLine("{0}", 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.

Değişken, her görevdeki nTasks yönteme yapılan çağrıdan önce kutulandığından Monitor.Enter her görev bir SynchronizationLockException özel durum oluşturur. Başka bir deyişle, her yöntem çağrısı diğerlerinden bağımsız ayrı bir değişken geçirilir. nTasks yöntemine yapılan çağrıda Monitor.Exit yeniden kutulanır. Bir kez daha bu, birbirinden bağımsız nTaskson yeni kutulanmış değişken ve yöntemi çağrısında Monitor.Enter oluşturulan on kutulanmış değişken oluşturur. Özel durum oluşturulur, çünkü kodumuz daha önce kilitlenmemiş yeni oluşturulan bir değişkende kilit bırakmaya çalışır.

Aşağıdaki örnekte gösterildiği gibi ve Exitçağırmadan Enter önce bir değer türü değişkeni kutulayabilir ve 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("{0} tasks started and executed.", nTasks);
      }
      catch (AggregateException e) {
         String msg = String.Empty;
         foreach (var ie in e.InnerExceptions) {
            Console.WriteLine("{0}", 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şitlenecek nesneyi seçerken, yalnızca özel veya iç nesnelere kilitlemelisiniz. İlişkili olmayan kod farklı amaçlarla kilitlenmek üzere aynı nesneleri seçebileceğinden, dış nesnelere kilitlenmeye neden olabilir.

Kilit için kullanılan nesne öğesinden MarshalByRefObjecttüretilirse, birden çok uygulama etki alanında bulunan bir nesne üzerinde eşitleme yapabileceğinizi unutmayın.

Kritik bölüm

Kritik bir bölümün başlangıcını Enter ve sonunu işaretlemek için ve Exit yöntemlerini kullanın.

Not

ve yöntemleri tarafından Enter sağlanan işlevsellik, C# içindeki kilit deyimi ve Visual Basic'teki SyncLock deyimi tarafından sağlanan işlevle aynıdır, ancak dil yapılarının yöntem aşırı yüklemesini Monitor.Enter(Object, Boolean) ve Monitor.Exit yöntemini bir try.Exit..finally bloğunu sunun.

Kritik bölüm bitişik yönergeler kümesiyse, yöntemi tarafından Enter alınan kilit, kapalı kodu kilitli nesneyle yalnızca tek bir iş parçacığının yürütebileceğ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 yöntemin tamamına yayılmışsa, kilitleme tesisi yöntemine yerleştirilip System.Runtime.CompilerServices.MethodImplAttribute oluşturucusunda System.Runtime.CompilerServices.MethodImplAttributedeğeri belirtilerek Synchronized gerçekleştirilebilir. Bu özniteliği kullandığınızda ve EnterExit yöntemi ç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

özniteliğinin geçerli iş parçacığının yöntem dönene kadar kilidi tutmasına neden olduğunu unutmayın; kilit daha önce serbest bırakılabilirse, özniteliği yerine yönteminin Monitor içindeki sınıfını, C# lock deyimini veya Visual Basic SyncLock deyimini kullanın.

Belirli bir nesneyi kilitleyip serbest bırakan ve Exit deyimlerinin üye veya sınıf sınırlarını ya da her ikisini birden aşması mümkün Enter 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.Pulseve Monitor.PulseAll yöntemlerini çağırabilirMonitor.Wait.

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. Hazır sıradaki ilk iş parçacığı varsa kilidi alır ve kritik bölüme girer. çağrılan Wait iş parçacığı, veya Monitor.PulseAll yöntemi kilidi tutan iş parçacığı tarafından çağrıldığında Monitor.Pulse bekleme kuyruğundan hazır kuyruğa taşınır (taşınabilmesi için, iş parçacığı bekleme kuyruğunun başında olmalıdır). çağıran Wait iş parçacığı kilidi yeniden alırsa yöntemi döndürür.

Kilidi tutan iş parçacığı çağırdığında Pulse, bekleme kuyruğunun başındaki iş parçacığı hazır kuyruğa taşınır. yöntemine yapılan PulseAll çağrı, bekleyen kuyruktan hazır kuyruğa tüm iş parçacıklarını taşır.

İzleyiciler ve bekleme tutamaçları

Sınıfın WaitHandle ve nesnelerin kullanımı Monitor 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, sınıfı tarafından Monitor temsil edilen rastgele bir sayı oluşturucunun tek bir örneğine erişimi eşitlemek için sınıfını Random kullanır. Örnek, her biri bir iş parçacığı havuzu iş parçacığında zaman uyumsuz olarak 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: {0:N2} (N={1:N0})",
                              (total * 1.0) / n, n);
        }
        catch (AggregateException e)
        {
            foreach (var ie in e.InnerExceptions)
                Console.WriteLine("{0}: {1}", 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 değişkenlere total erişim ve n ayrıca eşitlenmesi gerekir. Interlocked.Add yöntemi bu amaç için kullanılır.

Aşağıdaki örnekte sınıfın (veya SyncLock dil yapısıyla lock uygulanır), sınıfın ve sınıfın Interlocked birleştirilmiş kullanımı Monitor gösterilmektedirAutoResetEvent. Bir kaynağa eşitlenmiş ve eşitlenmemiş erişim sağlayan iki internal (C#içinde) veya Friend (Visual Basic'te) ve UnSyncResourcesınıflarını SyncResource 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 . SyncResource Sınıfı genel olmadığından, istemci kodunun hiçbiri eşitlenen 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 #{0}",
                              Thread.CurrentThread.ManagedThreadId);
            if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
                Thread.Sleep(2000);

            Thread.Sleep(200);
            Console.WriteLine("Stopping synchronized resource access on thread #{0}",
                              Thread.CurrentThread.ManagedThreadId);
        }
    }
}

internal class UnSyncResource
{
    // Do not enforce synchronization.
    public void Access()
    {
        Console.WriteLine("Starting unsynchronized resource access on Thread #{0}",
                          Thread.CurrentThread.ManagedThreadId);
        if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
            Thread.Sleep(2000);

        Thread.Sleep(200);
        Console.WriteLine("Stopping unsynchronized resource access on thread #{0}",
                          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ığı eşitlenmiş ve eşitlenmemiş erişim için yöntemini beş kez çağırır ThreadPool.QueueUserWorkItem(WaitCallback) . yönteminde ThreadPool.QueueUserWorkItem(WaitCallback) tek bir parametre, parametre kabul eden ve değer döndürmez bir temsilci bulunur. 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 çağırarak örnek sinyal alınana kadar engellemesini AutoResetEvent sağlar.

Yöntemine yapılan SyncUpdateResource her çağrı iç SyncResource.Access yöntemi çağırır ve ardından sayacını azaltmaya numOps yönelik yöntemini çağırırInterlocked.Decrement. 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ığı, tüm eşitlenen iş parçacıklarının kaynağa erişmesinin tamamlandığını belirterek sayacı sıfıra düşürdüyse, SyncUpdateResource yöntemi yöntemini çağırır EventWaitHandle.Set ve bu yöntem ana iş parçacığının yürütmeye devam etmesi için sinyal gönderir.

Yöntemine yapılan UnSyncUpdateResource her çağrı iç UnSyncResource.Access yöntemi çağırır ve ardından sayacını azaltmaya numOps yönelik yöntemini çağırırInterlocked.Decrement. 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ş çalışan iş parçacığı sayacı sıfır olarak azalttığında ve artık eşitlenmemiş iş parçacıklarının kaynağa erişmesi gerekmediğini gösterirse, UnSyncUpdateResource yöntem yöntemini çağırır EventWaitHandle.Set ve bu da 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öntem iş parçacıklarının ulaşıldığı sırayla çağrılır.