Me resulta curioso que sorprenda una típica implementación de "test and set":-)
Más que por la implementación de "mutexes" (multithread, intraproceso), la programación multithread me resulta especialmente compleja dado lo toscos que resultan los planificadores de threads/procesos de los sistemas operativos (incluso en el caso de RTOS, aunque en menor medida), sobretodo cuando hay muchos threads haciendo cálculo, donde un "quantum" de 10ms se vuelve eterno y con más de 20 threads de ese tipo, provocan que el planificador se torne ineficaz incluso a la hora de hacer E/S en otros threads (los threads de cálculo tienen prioridad sobre los de E/S, obviamente).
Cualquiera que haya trabajado con muchos threads de manera concurrente, sabe lo desastrosos que son los sistemas operativos al respecto de repartir tiempos, y que se le ha de "echar una mano" para que funcione con un reparto equitativo y predecible. Medidas útiles en el "mundo real" acerca de la programación multithread, resolución de colisiones, reparto de carga:
a) ["demasiado cálculo para el body"] Si hay muchos threads de cálculo ejecutándose de manera concurrente, tener en cuenta el "quantum" del sistema operativo (tiempo máximo para cálculo antes de que te interrumpa el "timer" mediante una IRQ hardware, depende del TICS_PER_SEC del S.O., normalmente de 100Hz a 3KHz). A mí me gusta que el equilibrio donde el número total de threads haciendo cálculo multiplicado por el "quantum", sea inferior a 0.5 segundos. Para devolver el "testimonio" de cálculo, se puede optar por:
- sched_yield() para POSIX (o SleepEx(0, TRUE) para Windows): devuelve el control si hay algún otro thread en estado "ready to run", si no, continúa con el thread en curso, hasta llegar al sobrepasar el "quantum" (no rearma el timer del quantum). Dependiendo del sistema operativo, el mero hecho de tener demasiados threads en estado "ready to run" puede poner en apuros al planificador (si hace un "round robin" estricto, hay pocos problemas, pero ojo con tocar la prioridad, pues puede desenvocar en un caso de "inversión de prioridades" que haga ir al sistema a trompicones). Haciendo una buena previsión para repartir el tiempo de ejecución, podemos tener bajo un kernel a 100Hz aplicaciones con cientos de threads que se comporten de manera muy suave, como si tuviesen un kernel a 10KHz (hace ligeramente más complejas las implementaciones, pues en lugar de concentrarte en el problema, tienes que tener en cuenta siempre al SO).
- sleep(0) para POSIX (o Sleep(0) para Windows): devuelve el control durante al menos un "quantum" (dependiendo del planificador, pasará a estar en alguno de los estados de "sleep"/"wait" o algún "pseudo ready to run").
b) ["muchos thread haciendo poco con un alto grado de concurrencia, con un alto grado de transacciones por segundo sostenidas"] Si los threads comparten datos, normalmente me he encontrado con dos grupos de casos:
- Productor / consumidor: hay threads que producen, dejan el resultado en una cola, y sólo se paran hasta llegar al límite del buffer. En este caso no hay problemas de exclusión mútua. Sería el caso análogo para threads que se usa entre procesos mediante "pipes", y los resultados son muy buenos, pero en el caso de datos independientes, claro (prácticamente no hay colisiones, sólo reparto de carga entre threads).
- Acceso a datos compartidos para transacciones diferentes: en este caso pueden existir zonas de sólo lectura, de lectura/escritura, susceptibles de ser cambiadas por cualquier thread. La solución obvia es añadir "mutexes" ("critical sections") para serializar el acceso... craso error: es MUY LENTO, dado que se acaba siendo código "mono thread", usando sólo una de las CPUs disponibles. Soluciones, dependiendo del problema e
Ya sé que está fuera de moda, pero la verdad es que me enamoré de su multitarea. Es clara, simple y potente. Los conceptos de exclusión están sintácticamente definidos en un "protected object" y en otras cosas.
Sé que parece anacrónico, pero creo que vale la pena echarle una mirada. Se aprende mucha multitarea sólo leyendo su sintaxis. Admito que no he hecho nada profesionalmente, mi trabajo no exige nada de eso, pero si he hecho experimentos que se me habrían complicado muchísimo en otros lenguajes.
Wooow
(Puntos:0)Vaya
(Puntos:5, Informativo)( http://www.voluntariado.net/ | Última bitácora: Domingo, 10 Junio de 2012, 21:48h )
Más que por la implementación de "mutexes" (multithread, intraproceso), la programación multithread me resulta especialmente compleja dado lo toscos que resultan los planificadores de threads/procesos de los sistemas operativos (incluso en el caso de RTOS, aunque en menor medida), sobretodo cuando hay muchos threads haciendo cálculo, donde un "quantum" de 10ms se vuelve eterno y con más de 20 threads de ese tipo, provocan que el planificador se torne ineficaz incluso a la hora de hacer E/S en otros threads (los threads de cálculo tienen prioridad sobre los de E/S, obviamente).
Cualquiera que haya trabajado con muchos threads de manera concurrente, sabe lo desastrosos que son los sistemas operativos al respecto de repartir tiempos, y que se le ha de "echar una mano" para que funcione con un reparto equitativo y predecible. Medidas útiles en el "mundo real" acerca de la programación multithread, resolución de colisiones, reparto de carga:
a) ["demasiado cálculo para el body"] Si hay muchos threads de cálculo ejecutándose de manera concurrente, tener en cuenta el "quantum" del sistema operativo (tiempo máximo para cálculo antes de que te interrumpa el "timer" mediante una IRQ hardware, depende del TICS_PER_SEC del S.O., normalmente de 100Hz a 3KHz). A mí me gusta que el equilibrio donde el número total de threads haciendo cálculo multiplicado por el "quantum", sea inferior a 0.5 segundos. Para devolver el "testimonio" de cálculo, se puede optar por:
- sleep(0) para POSIX (o Sleep(0) para Windows): devuelve el control durante al menos un "quantum" (dependiendo del planificador, pasará a estar en alguno de los estados de "sleep"/"wait" o algún "pseudo ready to run").
b) ["muchos thread haciendo poco con un alto grado de concurrencia, con un alto grado de transacciones por segundo sostenidas"] Si los threads comparten datos, normalmente me he encontrado con dos grupos de casos:
- Acceso a datos compartidos para transacciones diferentes: en este caso pueden existir zonas de sólo lectura, de lectura/escritura, susceptibles de ser cambiadas por cualquier thread. La solución obvia es añadir "mutexes" ("critical sections") para serializar el acceso... craso error: es MUY LENTO, dado que se acaba siendo código "mono thread", usando sólo una de las CPUs disponibles. Soluciones, dependiendo del problema e
Has probado Ada ?
(Puntos:2)( http://barrapunto.com/ | Última bitácora: Viernes, 29 Diciembre de 2017, 18:26h )
Ya sé que está fuera de moda, pero la verdad es que me enamoré de su multitarea. Es clara, simple y potente. Los conceptos de exclusión están sintácticamente definidos en un "protected object" y en otras cosas.
Sé que parece anacrónico, pero creo que vale la pena echarle una mirada. Se aprende mucha multitarea sólo leyendo su sintaxis. Admito que no he hecho nada profesionalmente, mi trabajo no exige nada de eso, pero si he hecho experimentos que se me habrían complicado muchísimo en otros lenguajes.
Me viene estupendamente algo así
(Puntos:0)A ver si el artículo me sirve para asentar los conceptos.