Una diferencia potencialmente significativa podría ser la equidad de la distribución de recursos. No conozco los detalles de la implementación de la familia semget/semop
, pero sospecho que normalmente se implementa como un semáforo "tradicional" en lo que respecta a la programación. En general, creo que los hilos liberados se manejan en una base FIFO (el primero que espera que el semáforo se libere primero).No creo que esto ocurra con el bloqueo de archivos, ya que sospecho (de nuevo, solo estoy adivinando) que el manejo no se realiza a nivel del kernel.
Tenía el código existente sentado para probar los semáforos para propósitos de IPC, por lo que comparé las dos situaciones (una usando semop
y otra usando lockf
). Hice la prueba de un pobre y simplemente corrí a las instancias de la aplicación. El semáforo compartido se usó para sincronizar el inicio. Al ejecutar la prueba de semop, ambos procesos terminaron 3 millones de bucles casi sincronizados. El loopf lockf, por otro lado, no era tan justo. Un proceso normalmente termina mientras que el otro solo ha completado la mitad de los bucles.
El ciclo para la prueba de semop se veía como el siguiente. Las funciones semwait
y semsignal
son solo envoltorios para las llamadas semop
.
ct = myclock();
for (i = 0; i < loops; i++)
{
ret = semwait("test", semid, 0);
if (ret < 0) { perror("semwait"); break; }
if ((i & 0x7f) == 0x7f)
printf("\r%d%%", (int)(i * 100.0/loops));
ret = semsignal(semid, 0);
if (ret < 0) { perror("semsignal"); break; }
}
printf("\nsemop time: %d ms\n", myclock() - ct);
El tiempo de ejecución total para ambos métodos fue casi la misma, aunque la versión lockf realidad era más rápido en general a veces debido a la injusticia de la programación. Una vez que el primer proceso haya finalizado, el otro proceso tendrá acceso no disputado durante aproximadamente 1,5 millones de iteraciones y se ejecutará extremadamente rápido.
Cuando se ejecuta sin prueba (proceso único que obtiene y libera los bloqueos), la versión semop fue más rápida. Tomó aproximadamente 2 segundos para 1 millón de iteraciones, mientras que la versión de lockf tomó aproximadamente 3 segundos.
Este ensayo se realizó de la siguiente versión:
[]$ uname -r
2.6.11-1.1369_FC4smp
Recuerdo que pthread_mutex_t en una memoria compartida a veces causa problemas, si no recuerdo mal en el kernel 2.4.x. ¿Sabes algo sobre eso? – DarkDust
@DarkDust: versiones de kernel anteriores a 2.6.algo (pero hace muchos años) tenía una implementación pthread diferente, que de hecho no era adecuada para el control entre procesos. Esto es historia. De todos modos, la llamada 'init' correspondiente le indicará a la vuelta si el atributo' pshared' no es compatible con la implementación. –
¿Sacrificas la portabilidad con esta técnica? – bstpierre