Polls

Escribirías en el wiki de codepixel?
 

Login Form






Lost Password?
No account yet? Register

Wiki Codepixel

Visita el Wiki de programación gráfica de codepixel . Podrás incluir los enlaces que creas interesantes para desarrollar videojuegos, motores de render, demos, etc.

Quién está online?

We have 42 guests online

Syndicate

Inicio
Usando Spin Locks PDF Print E-mail
Written by Javier Loureiro   
Friday, 13 March 2009

El tema de sincronizar varios hilos de forma óptima es bastante complicado. El sistema operativo nos ofrece varias posibilidades de sincronismo que garantizan un correcto uso de recursos compartidos, permitiendo que varios núcleos accedan a la misma zona de memoria sin pisarse. El problema es que este sincronismo suele ser especialmente lento si se usa de forma intensiva, porque nuestro programa tiene que ejecutar código que está en "espacio de kernel", o sea, que tiene que cambiar de tarea, implicar al kernel del sistema (invalidando caches), y despues volver a activar nuestro programa. Fácilmente unos miles de ciclos.

Si estos bloqueos son en sistios conocidos del sistema, y se usan de forma racional, no hay problema. Pero al programar gráficos y cosas de "alto rendimiento", esto puede reventar el rendimiento de la aplicación. Un ejemplo es el insertar información en estructuras de aceleración en paralelo, etc.

Una solución muy usada son los "spin locks ". Exactamente qué significa esto? Pues es tan sencillo como hacer un búcle que compruebe una variable continuamente. Cuando un hilo entra, la pone a "falso" y el resto se quedan en un bucle esperando hasta que sea verdadero.

Esto que parece sencillo, tiene 2 problemas. El primero es el evidente gasto de CPU. Si el código protegido por el spin lock es grande, entonces los otros hilos perderán muchos ciclos en un absurdo bucle... Pero si el código es pequeño (como un simple cambio en una variable, una insercción en una lista, etc) y además, el tiempo de espera preveemos que sea pequeño, entonces compensará ejecutar este bucle, antes de perderse en un bloqueo de sistema.

El otro problema es el pensar en cómo escribimos el código. En ensamblador, una instrucción de C tan sencillo como "a=b+1" tiene varios pasos:

- calcular la dirección de b

- cargar  b en un registro

- incrementar el registro en 1

- mover el valor del registro en a

Qué pasa si hay muchos hilos? pues cuando movemos el valor al registro, el otro thread no se entera, y puede operar en paralelo con ese dato. Así, mientras movemos b a un registro, e incrementamos 1, otro hilo puede haber modificado b, con lo que el resultado final será incorrecto. Además, los compiladores pueden meter más instrucciones entre el principio y el final del incremento, para aprovechar ciclos o ir adelantando tiempo antes de la escritura en b, por lo que las probabilidades de cambio aumentan.No hablemos de temas de cache, ya que podemos escribir b en una memoria intermedia, y otro hilo no darse cuenta de todo esto hasta pasados unos ciclos.

Incrementar una variable es algo que ocurre mucho en entornos multihilo, por ejemplo, un contador de referencias. Seria bastante fuerte tener que hacer un bloqueo de sistema en cada uso de un "smart pointer".

La solución es hacer ese incremento "atómico". O sea, que en 1 sola instrucción podamos resolver el incremento, evitando que el valor de la variable incrementada pueda ser modificado en otro hilo. Para ello, existen una familia de instrucciones que permiten operar de forma atómica en las variables. Este es el enlace a la lista de operaciones de microsoft .

Un spinlock aprovecha esto para comprobar que el bucle realmente bloquea el acceso. El código seria algo como:

  //  inicialmente, lock es el puntero a una variable que contiene 0 (desbloqueado)

  // esperamos a que lock valga 0

  while (::InterlockedExchange( (LONG *) lock, 1) != 0)
  {
     // puedo llamar a Switch thread aqui para que el procesador se ocupe de otras cosas más importantes antes que yo.

  }  

 // hago lo que tenga que hacer

 // restauro el valor de lock, poniendolo a 0

  ::InterlockedExchange( (volatile LONG *) lock, 0);

 

 

Comentarios
AgregarnuevoBuscar
- Alberto Pérez-Bermejo - Muy útil     | 81.60.131.xxx | 2009-03-13 22:07:30
Suena realmente interesante. Muchas gracias por el tip.
- Ruben Penalva - Libro sobre concurrencia     | 212.0.110.xxx | 2009-03-16 13:46:33
Hi,
hay un libro chulo llamado "The art of multiprocessor programming" que habla de este tema precisamente en sus primeros capitulos. Teneis el link aqui: http://www.amazon.com/Art-Multiprocessor-Programming-Maurice-Herlihy/dp/0123705916/

Un saludo,
Ruben Penalva
- derethor - re: Libro sobre concurrencia   | Super Administrator | 2009-03-16 16:11:55
añadido al wiki


Ruben Penalva escribió:
Hi,
hay un libro chulo llamado "The art of multiprocessor programming" que habla de este tema precisamente en sus primeros capitulos. Teneis el link aqui: http://www.amazon.com/Art-Multiprocessor-Programming-Maurice-Herlihy/dp/0123705916/

Un saludo,
Ruben Penalva
ent   | 89.131.192.xxx | 2009-03-17 23:29:47
Miedo me da ver código como ese en plan LockLess. Nada aconsejable desde luego. Ni para novatos ni para expertos.

El código de arriba por ejemplo, segun lo que metas dentro del lock puede dar algun problema si no sabes bien lo que estas haciendo, segun la coherencia de caches entre nucleos, etc. Vamos, una puerta abierta al infierno... :)

La sección crítica de Windows soporta spinlock de manera nativa. Mucho mas recomendable.
Escribir comentario
Nombre:
Email:
 
Website:
Título:
Código UBB:
[b] [i] [u] [url] [quote] [code] [img] 
 
Security Image
Por favor introduce el codigo anti-spam que puedes leer en la imagen.

Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved.



menéameDigg!Del.icio.us!Google!Technorati!Yahoo!
Last Updated ( Friday, 13 March 2009 )
 
< Prev   Next >

Lista de Correo

visita la lista de correo de codepixel. Es una lista abierta, asi que podrás subscribirte y preguntar tus dudas de programación, compartir tus opiniones, aportar ideas, y formar parte de la comunidad codepixelera.

 

Visita la antigua página

Image