Pregunta

Una pregunta bastante básica, pero no la veo en ningún lado.

Digamos que tenemos una estructura global (en C) así:

struct foo {
  int written_frequently1;
  int read_only;
  int written_frequently2;
};

Me parece claro que si tenemos muchos hilos que leen y escriben, necesitamos un semáforo (u otro bloqueo) en los miembros written_frequency , incluso para leer, ya que no podemos ser 100% seguro de que las asignaciones a esta estructura serán atómicas.

Si queremos muchos hilos para leer el miembro read_only , y ninguno para escribir, ¿necesitamos un semáforo en el acceso a la estructura solo para leer?

(Me inclino a decir que no, porque el hecho de que las ubicaciones inmediatamente anteriores y posteriores se cambien constantemente no debería afectar al miembro read_only , y múltiples hilos que leen el valor no deberían interferir entre ellos. Pero no estoy seguro.)


[Editar: ahora me doy cuenta de que debería haber hecho esta pregunta mucho mejor, para aclarar muy específicamente lo que quería decir. Naturalmente, en realidad no comprendí todos los problemas involucrados cuando hice la pregunta por primera vez. Por supuesto, si ahora edito completamente la pregunta, arruinaré todas estas excelentes respuestas. Lo que quise decir es más como:

struct bar {
  char written_frequently1[LONGISH_LEN];
  char read_only[LONGISH_LEN];
  char written_frequently2[LONGISH_LEN];
};

El problema principal sobre el que pregunté es que, dado que estos datos son parte de una estructura, ¿están influenciados por los otros miembros de la estructura, y podría influirlos a cambio?

El hecho de que los miembros fueran int y, por lo tanto, las escrituras probablemente sean atómicas, en realidad es solo una pista falsa en este caso.]

¿Fue útil?

Solución 10

Muchas gracias a todos los grandes respondedores (y por todas las excelentes respuestas).

Para resumir:

Si hay un miembro de solo lectura de una estructura (en nuestro caso, si el valor se establece una vez, mucho antes de que cualquier hilo pueda querer leerlo), los hilos que leen este miembro no necesitan bloqueos, mutexes, semáforos , o cualquier otra protección de concurrencia.

Esto es cierto incluso si se escribe a los otros miembros con frecuencia. El hecho de que las diferentes variables sean parte de la misma estructura no hace ninguna diferencia.

Otros consejos

Necesita un mutex para garantizar que una operación sea atómica. Entonces, en este caso particular, es posible que no necesite un mutex en absoluto. Específicamente, si cada hilo escribe en un elemento y la escritura es atómica y el nuevo valor es independiente del valor actual de cualquier elemento (incluido él mismo), no hay problema.

Ejemplo: cada uno de varios hilos actualiza un " last_updated_by " variable que simplemente registra el último hilo que lo actualizó. Claramente, mientras la variable en sí se actualice atómicamente, no se producirán errores.


Sin embargo, do necesita un mutex para garantizar la coherencia si un hilo lee o escribe más de un elemento a la vez, particularmente porque menciona bloquear un elemento en lugar de la estructura completa .

Ejemplo: un hilo actualiza el " día " ;, " mes " y "año" elementos de una estructura. Esto debe suceder atómicamente, para que otro hilo no lea la estructura después del '' mes '' incrementos pero antes del "día" se ajusta a 1, para evitar fechas como el 31 de febrero. Tenga en cuenta que debe honrar el mutex al leer; de lo contrario, puede leer un valor erróneo y medio actualizado.

Si el miembro read_only es en realidad de solo lectura, entonces no hay peligro de que los datos se modifiquen y, por lo tanto, no hay necesidad de sincronización. Estos podrían ser datos que se configuran antes de que se inicien los hilos.

Desea la sincronización de cualquier dato que se pueda escribir, independientemente de la frecuencia.

" Solo lectura " es un poco engañoso, ya que la variable se escribe al menos una vez cuando se inicializa. En ese caso, aún necesita una barrera de memoria entre la escritura inicial y las lecturas posteriores si están en diferentes subprocesos, o de lo contrario podrían ver el valor no inicializado.

¡Los lectores también necesitan mutexes!

Parece haber una idea errónea común de que los mutexes son solo para escritores y que los lectores no los necesitan. Esto está mal, y esta idea errónea es responsable de los errores que son extremadamente difíciles de diagnosticar.

He aquí por qué, en forma de ejemplo.

Imagine un reloj que se actualiza cada segundo con el código:

if (++seconds > 59) {        // Was the time hh:mm:59?
   seconds = 0;              // Wrap seconds..
   if (++minutes > 59)  {    // ..and increment minutes.  Was it hh:59:59?
     minutes = 0;            // Wrap minutes..
     if (++hours > 23)       // ..and increment hours.  Was it 23:59:59?
        hours = 0;           // Wrap hours.
    }
}

Si el código no está protegido por un mutex, otro hilo puede leer las variables horas , minutos y segundos mientras se realiza una actualización en progreso. Siguiendo el código anterior:

[Start just before midnight] 23:59:59
[WRITER increments seconds]  23:59:60
[WRITER wraps seconds]       23:59:00
[WRITER increments minutes]  23:60:00
[WRITER wraps minutes]       23:00:00
[WRITER increments hours]    24:00:00
[WRITER wraps hours]         00:00:00

El tiempo no es válido desde el primer incremento hasta la operación final seis pasos más tarde . Si un lector revisa el reloj durante este período, verá un valor que puede ser no solo incorrecto sino ilegal . Y dado que es probable que su código dependa del reloj sin que muestre la hora directamente, esta es una fuente clásica de "rebote". errores que son notoriamente difíciles de rastrear.

La solución es simple.

Rodee el código de actualización del reloj con un mutex y cree una función de lector que también bloquee el mutex mientras se ejecuta. Ahora el lector esperará hasta que se complete la actualización, y el escritor no cambiará los valores a mitad de la lectura.

No.

En general, necesita semáforos para evitar el acceso concurrente a los recursos (un int en este caso). Sin embargo, dado que el miembro read_only es de solo lectura, no cambiará entre / durante los accesos. Tenga en cuenta que ni siquiera tiene que ser una lectura atómica & # 8212; si nada cambia, siempre estás a salvo.

¿Cómo está configurando read_only inicialmente?

Si todos los hilos solo están leyendo, no necesita un semáforo.

Puede que le guste leer cualquiera de estos documentos en programación práctica sin bloqueo , o simplemente disección y comprensión de los fragmentos proporcionados.

Ocultaría cada campo detrás de una llamada de función. Los campos de solo escritura tendrían un semáforo. El solo lectura solo devuelve el valor.

Agregar a respuestas anteriores:

  1. En este caso, el paradigma de sincronización natural es la exclusión mutua, no los semáforos.
  2. Estoy de acuerdo en que no necesita ningún mutex en las variables de solo lectura.
  3. Si la parte de lectura-escritura de la estructura tiene restricciones de consistencia, en general necesitará uno mutex para todos para mantener las operaciones atómicas.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top