Jak synchronizovat přístup ke sdílenému prostředku v prostředí s více podprocesy pomocí aplikace Visual C#

Souhrn

Více úkolů lze provést v Microsoft Visual C# aplikace současně pomocí multithreading. Spuštění různých podprocesů zároveň dokončit různé úkoly můžete multithreading. Podprocesy také zvyšují výkon a odezvu aplikací.

Vzhledem k tomu, že více vláken může přistupovat k prostředku současně, můžete synchronizovat s ostatními částmi aplikace jednotlivých vláken. Tento článek popisuje některé běžné scénáře programování s využitím podprocesů a vysvětluje způsob synchronizace přístupu několika podprocesů ke sdílenému prostředku.

zpět na horní

Nápověda k ochraně globálních údajů v modulech v prostředí s více podprocesy

Veřejná pole metod jsou přístupná všem podprocesům v aplikaci. Pokud chcete synchronizovat přístup k veřejným polím, můžete použít vlastnost místo pole a řídit přístup pomocí objektu ReaderWriterLock . Chcete-li to provést, postupujte takto:
  1. Spusťte aplikaci Visual Studio.
  2. V nabídce soubor přejděte na příkaz Nový a klepněte na příkaz projekt.
  3. Klepněte na tlačítko
    Projekty visual C# v části Typy projektua klepněte na tlačítko Aplikace konzoly ve skupinovém rámečku
    Šablony.

    Poznámka: V aplikaci Visual Studio 2005 nebo Visual Studio 2008 klepněte na tlačítko Visual C# v části Typy projektua potom klepněte na tlačítko Aplikace konzoly ve skupinovém rámečku
    Šablony.
  4. Do textového pole název zadejte
    Název MultiThreadApplicationa klepněte na tlačítko
    OK.
  5. Nahraďte existující kód v modulu Class1.cs následujícím kódem.

    Poznámka: V aplikaci Visual Studio 2005 a Visual Studio 2008 výchozí soubor je Program.cs.
    using System;using System.Threading;

    namespace MultiThreadApplication
    {
    class Class1
    {
    private ReaderWriterLock rwl = new ReaderWriterLock();
    private long myNumber;
    public long Number // the Number property
    {
    get
    {
    //Acquire a read lock on the resource.
    rwl.AcquireReaderLock(Timeout.Infinite);
    try
    {
    Console.WriteLine("Thread:{0} starts getting the Number", Thread.CurrentThread.GetHashCode());
    Thread.Sleep(50);
    Console.WriteLine("Thread:{0} got the Number", Thread.CurrentThread.GetHashCode());

    }
    finally
    {
    //Release the lock.
    rwl.ReleaseReaderLock();
    }
    return myNumber;
    }
    set
    {
    //Acquire a write lock on the resource.
    rwl.AcquireWriterLock(Timeout.Infinite);
    try
    {
    Console.WriteLine("Thread: {0} start writing the Number", Thread.CurrentThread.GetHashCode());
    Thread.Sleep(50);
    myNumber = value;
    Console.WriteLine("Thread: {0} written the Number", Thread.CurrentThread.GetHashCode());
    }
    finally
    {
    //Release the lock.
    rwl.ReleaseWriterLock();
    }
    }
    }

    [STAThread]
    static void Main(string[] args)
    {
    Thread []threadArray = new Thread[20];
    int threadNum;


    Class1 Myclass = new Class1();
    ThreadStart myThreadStart = new ThreadStart(Myclass.AccessGlobalResource);

    //Create 20 threads.
    for( threadNum = 0; threadNum < 20; threadNum++)
    {
    threadArray[threadNum] = new Thread(myThreadStart);
    }

    //Start the threads.
    for( threadNum = 0; threadNum < 20; threadNum++)
    {
    threadArray[threadNum].Start();
    }

    //Wait until all the thread spawn out finish.
    for( threadNum = 0; threadNum < 20; threadNum++)
    threadArray[threadNum].Join();

    Console.WriteLine("All operations have completed. Press enter to exit");
    Console.ReadLine();
    }

    public void AccessGlobalResource()
    {
    Random rnd = new Random();
    long theNumber;

    if (rnd.Next() % 2 != 0)
    theNumber = Number;
    else
    {
    theNumber = rnd.Next();
    Number = theNumber;
    }

    }
    }
    }

  6. Sestavte projekt a spusťte aplikaci.
zpět na horní

Nápověda k vaší třídy bezpečným

Více vláken může pokusit o přístup k objektu současně. Po více než jedno vlákno soupeří o přístup k objektu ve stejnou dobu, některé podprocesy obdržet neplatný stav Pokud jiný podproces upravuje zdroje současně. Například pokud jeden podproces čte pole objektu, zatímco jiný podproces upravuje pole, první podproces obdržet neplatný stav pole. Tato situace je označována jako spor.

K této situaci vyhnout, můžete pomoci chránit kritické části kódu před vznikem sporu pomocí zámků. Zámek, který je reprezentován klíčové slovo Visual C# lock prohlášení, umožňuje získání výhradních práv pro objekt jediný podproces. Následující příklad kroky představují použití zámků:
  1. Otevřete Visual Studio.
  2. V nabídce soubor přejděte na příkaz Nový a klepněte na příkaz projekt.
  3. Klepněte na tlačítko
    Projekty visual C# v části Typy projektua klepněte na tlačítko Aplikace konzoly ve skupinovém rámečku
    Šablony.

    Poznámka: V aplikaci Visual Studio 2005 nebo Visual Studio 2008 klepněte na tlačítko Visual C# v části Typy projektua potom klepněte na tlačítko Aplikace konzoly ve skupinovém rámečku
    Šablony.
  4. Do textového pole název zadejte
    MultiThreadLockApplicationa klepněte na tlačítko
    OK.
  5. Nahraďte existující kód v modulu Class1.cs následujícím kódem:
    using System;using System.Threading;

    namespace MultiThreadLockApplication
    {
    class Student
    {
    private static string myTeacherName = "Bill";
    private string myName = "Grace";
    private static object somePrivateStaticObject = new Object();

    public static string TeacherName
    {
    get
    {
    string theName;

    // Synchronize access to the shared member.
    lock(somePrivateStaticObject)
    {
    Console.WriteLine("Thread {0} starts to get the teacher's name",Thread.CurrentThread.GetHashCode());
    theName = myTeacherName;

    // Wait for 0.3 second.
    Thread.Sleep(300);
    Console.WriteLine("Thread {0} finished to get the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), theName);
    }
    return theName;
    }

    set
    {
    lock(somePrivateStaticObject)
    {
    Console.WriteLine("Thread {0} starts to set the teacher's name.", Thread.CurrentThread.GetHashCode());
    myTeacherName = value;

    // Wait for 0.3 second.
    Thread.Sleep(300);
    Console.WriteLine("Thread {0} finished to set the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), value);
    }
    }
    }

    public string GetName()
    {
    string theName;
    lock(this)
    {
    Console.WriteLine("Thread {0} starts to get the student's name.", Thread.CurrentThread.GetHashCode());
    theName = myName;

    // Wait for 0.3 second.
    Thread.Sleep(300);
    Console.WriteLine("Thread {0} finished to get the student's name:{1}", Thread.CurrentThread.GetHashCode(), theName);
    return theName;
    }
    }

    public string SetName(string NewName)
    {
    string theOldName;
    lock(this)
    {
    Console.WriteLine("Thread {0} starts to set the student's name.", Thread.CurrentThread.GetHashCode());
    theOldName = myName;
    myName = NewName;

    // Wait for 0.3 second.
    Thread.Sleep(300);
    Console.WriteLine("Thread {0} finished to set the student's name:{1}", Thread.CurrentThread.GetHashCode(), NewName);
    }
    return theOldName;
    }
    }

    class Class1
    {
    public static int WorkItemNum = 20;
    public static AutoResetEvent Done = new AutoResetEvent(false);

    public static void AccessClassResource(object state)
    {
    Random rnd = new Random();
    string theName;
    Student AStudent = (Student) state;

    if( (rnd.Next() %2) != 0)
    {
    if( (rnd.Next() %2) != 0)
    {
    switch (rnd.Next() %3 )
    {
    case 0:
    Student.TeacherName = "Tom";
    break;
    case 1:
    Student.TeacherName = "Mike";
    break;
    case 2:
    Student.TeacherName = "John";
    break;
    }
    }
    else
    {
    theName = Student.TeacherName;
    }
    }
    else
    {
    if( (rnd.Next() %2) != 0)
    {
    switch (rnd.Next() %3 )
    {
    case 0:
    AStudent.SetName("Janet");
    break;
    case 1:
    AStudent.SetName("David");
    break;
    case 2:
    AStudent.SetName("Ben");
    break;
    }
    }
    else
    {
    theName = AStudent.GetName();
    }
    }

    if(Interlocked.Decrement( ref WorkItemNum) == 0)
    {
    Done.Set();
    }
    }

    [STAThread]
    static void Main(string[] args)
    {
    int threadNum;
    Student AStudent = new Student();

    // Queue up 20 work items in the ThreadPool.
    for (threadNum = 0 ; threadNum <= WorkItemNum -1 ; threadNum++)
    {
    ThreadPool.QueueUserWorkItem(new WaitCallback(AccessClassResource),AStudent);
    }

    Done.WaitOne();
    Console.WriteLine("All operations have completed. Press enter to exit");
    Console.ReadLine();
    }
    }
    }
  6. Sestavte projekt a spusťte aplikaci.
zpět na horní

Odkazy

Další informace naleznete na následujících webech Microsoft Developer Network (MSDN):zpět na horní
Vlastnosti

ID článku: 816161 - Poslední kontrola: 12. 1. 2017 - Revize: 2

Váš názor