Como sincronizar o acesso a um recurso partilhado num ambiente multithreading utilizando o Visual C#

Traduções de Artigos Traduções de Artigos
Artigo: 816161 - Ver produtos para os quais este artigo se aplica.
Expandir tudo | Reduzir tudo

Nesta página

Sumário

Pode efectuar várias tarefas nas aplicações do Microsoft Visual C# em simultâneo utilizando multithread. O multithreading pode iniciar diferentes threads para concluir tarefas diferentes ao mesmo tempo. O multithreading melhora também o desempenho e capacidade de resposta das aplicações.

Uma vez que vários threads podem aceder um recurso ao mesmo tempo, poderá sincronizar threads individuais com outras partes do programa. Este artigo descreve alguns cenários comuns com programação multithread e explica como sincronizar o acesso a um recurso partilhado entre vários threads.

Ajudar a proteger os dados em módulos num ambiente multithreaded globais

Os campos públicos métodos são acessíveis a todos os threads da aplicação. Para sincronizar o acesso aos campos públicos, pode utilizar a propriedade em vez do campo e utilizar um objecto ReaderWriterLock para controlar o acesso. Para o fazer, siga estes passos:
  1. Inicie o Microsoft Visual Studio.
  2. No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
  3. Clique em Visual C# Projects em Project Types e clique em Console Application em modelos .

    Nota No Visual Studio 2005 ou no Visual Studio 2008, clique em Visual C# em Project Types e, em seguida, clique em Aplicação de consola em modelos .
  4. Na caixa de texto nome , escreva MultiThreadApplication e, em seguida, clique em OK .
  5. Substitua o código existente com o seguinte código Class1.cs.

    Nota No Visual Studio 2005 e no Visual Studio 2008, o ficheiro predefinido é sistema 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. Criar o projecto e, em seguida, execute a aplicação.

Ajudar a criar a classe de segurança de thread

Vários threads poderão tentar aceder a um objecto ao mesmo tempo. Quando mais do que um thread competes para aceder a um objecto ao mesmo tempo, alguns threads poderão receber um estado inválido se outro thread modifica o recurso ao mesmo tempo. Por exemplo, se um thread de ler o campo de objecto enquanto outro thread está a modificar o campo, o thread primeiro poderão receber um estado inválido do campo. Esta situação é denominada uma condição de corrida.

Para evitar esta situação, pode ajudar a proteger secções críticas do código de condições de conflito entre tarefas concorrentes utilizando bloqueios. Um bloqueio, representado pelo bloqueio da palavra-chave do Visual C# declaração, permite que um único thread de execução para obter direitos de execução exclusiva no objecto. Os seguintes passos de exemplo demonstram bloqueios:
  1. Abra o Visual Studio.
  2. No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
  3. Clique em Visual C# Projects em Project Types e clique em Console Application em modelos .

    Nota No Visual Studio 2005 ou no Visual Studio 2008, clique em Visual C# em Project Types e, em seguida, clique em Aplicação de consola em modelos .
  4. Na caixa de texto nome , escreva MultiThreadLockApplication e, em seguida, clique em OK .
  5. Substitua o código existente com o seguinte código no sistema Class1.cs:
    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. Criar o projecto e, em seguida, execute a aplicação.

Referências

Para mais informações, consulte os seguintes Web sites da Microsoft Developer Network (MSDN):
Thread agrupamento
http://msdn2.microsoft.com/en-us/library/0ka9477y(vs.71).aspx
ReaderWriterLock
http://msdn2.microsoft.com/en-us/library/bz6sth95(vs.71).aspx
Classe ReaderWriterLock
http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlock(vs.71).aspx

Propriedades

Artigo: 816161 - Última revisão: 14 de julho de 2008 - Revisão: 3.1
A informação contida neste artigo aplica-se a:
  • Microsoft Visual C# 2008 Express Edition
  • Microsoft Visual C# 2005 Express Edition
  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
Palavras-chave: 
kbmt kbthreadsync kbthread kbhowtomaster KB816161 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 816161

Submeter comentários

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com