Cómo sincronizar el acceso a un recurso compartido en un entorno de subprocesamiento múltiple con C#

Seleccione idioma Seleccione idioma
Id. de artículo: 816161 - Ver los productos a los que se aplica este artículo
Expandir todo | Contraer todo

En esta página

Resumen

Puede realizar varias tareas en las aplicaciones de Microsoft Visual C# al mismo tiempo mediante el subprocesamiento múltiple. Subprocesamiento múltiple puede iniciar diferentes subprocesos para realizar tareas diferentes al mismo tiempo. Subprocesamiento múltiple también mejora el rendimiento y capacidad de respuesta de las aplicaciones.

Puesto que varios subprocesos pueden tener acceso a un recurso al mismo tiempo, puede que desee sincronizar subprocesos individuales con otras partes del programa. En este artículo describe algunos escenarios comunes con programación de subprocesamiento múltiple y se explica cómo sincronizar el acceso a un recurso compartido entre varios subprocesos.

Contribuir a proteger sus datos globales en los módulos en un entorno multiproceso

Los campos públicos en los métodos son accesibles para todos los subprocesos en la aplicación. Para sincronizar el acceso a los campos públicos, puede utilizar la propiedad en lugar del campo y utilizar un objeto ReaderWriterLock para controlar el acceso. Para ello, siga estos pasos:
  1. Inicie Microsoft Visual Studio.
  2. En el menú archivo , seleccione nuevo y, a continuación, haga clic en proyecto .
  3. Haga clic en Proyectos de Visual C# en Tipos de proyecto y haga clic a continuación, en Aplicación de consola bajo plantillas .

    Nota En Visual Studio 2005 o en Visual Studio 2008, haga clic en C# en Tipos de proyecto y, a continuación, haga clic en Aplicación de consola , bajo plantillas .
  4. En el cuadro de texto nombre , escriba MultiThreadApplication y, a continuación, haga clic en Aceptar .
  5. Reemplace el código existente con el código siguiente en Class1.cs.

    Nota En Visual Studio 2005 y Visual Studio 2008, el archivo predeterminado es 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. Genere el proyecto y, a continuación, ejecute la aplicación.

Ayuda para crear una clase segura para subprocesos

Varios subprocesos pueden intentar el acceso a un objeto al mismo tiempo. Cuando más de un subproceso compite para obtener acceso a un objeto al mismo tiempo, algunos subprocesos pueden aparecer un estado no válido si otro subproceso modifica el recurso al mismo tiempo. Por ejemplo, si un subproceso lee el campo del objeto mientras otro subproceso está modificando el campo, el primer subproceso recibe un estado no válido del campo. Esta situación se denomina una condición de anticipación.

Para evitar esta situación, puede ayudar a proteger las secciones críticas del código de condiciones de anticipación mediante bloqueos. Un bloqueo, representado por el bloqueo de palabra clave de C# Statement, permite que un único subproceso de ejecución obtener derechos de ejecución exclusivos sobre un objeto. Los pasos de ejemplo siguiente muestran bloqueos:
  1. Abra Visual Studio.
  2. En el menú archivo , seleccione nuevo y, a continuación, haga clic en proyecto .
  3. Haga clic en Proyectos de Visual C# en Tipos de proyecto y haga clic a continuación, en Aplicación de consola bajo plantillas .

    Nota En Visual Studio 2005 o en Visual Studio 2008, haga clic en C# en Tipos de proyecto y, a continuación, haga clic en Aplicación de consola , bajo plantillas .
  4. En el cuadro de texto nombre , escriba MultiThreadLockApplication y, a continuación, haga clic en Aceptar .
  5. Reemplace el código existente con el código siguiente en 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. Genere el proyecto y, a continuación, ejecute la aplicación.

Referencias

Para obtener más información, consulte los sitios Web de Microsoft Developer Network (MSDN) siguientes:
Subproceso agrupación
http://msdn2.microsoft.com/en-us/library/0ka9477y(vs.71).aspx
ReaderWriterLock
http://msdn2.microsoft.com/en-us/library/bz6sth95(vs.71).aspx
Clase ReaderWriterLock
http://msdn2.microsoft.com/en-us/library/system.threading.readerwriterlock(vs.71).aspx

Propiedades

Id. de artículo: 816161 - Última revisión: lunes, 14 de julio de 2008 - Versión: 3.1
La información de este artículo se refiere 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
Palabras clave: 
kbmt kbthreadsync kbthread kbhowtomaster KB816161 KbMtes
Traducción automática
IMPORTANTE: Este artículo ha sido traducido por un software de traducción automática de Microsoft (http://support.microsoft.com/gp/mtdetails) en lugar de un traductor humano. Microsoft le ofrece artículos traducidos por un traductor humano y artículos traducidos automáticamente para que tenga acceso en su propio idioma a todos los artículos de nuestra base de conocimientos (Knowledge Base). Sin embargo, los artículos traducidos automáticamente pueden contener errores en el vocabulario, la sintaxis o la gramática, como los que un extranjero podría cometer al hablar el idioma. Microsoft no se hace responsable de cualquier imprecisión, error o daño ocasionado por una mala traducción del contenido o como consecuencia de su utilización por nuestros clientes. Microsoft suele actualizar el software de traducción frecuentemente.
Haga clic aquí para ver el artículo original (en inglés): 816161

Enviar comentarios

 

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