windows - tagger - tag folders
Accediendo a un solo archivo con mĂșltiples hilos (4)
Puedes hacerlo de esa manera ...
El primer hilo con acceso de lectura / escritura debe crear primero un archivo:
FileHandle := CreateFile(
PChar(FileName),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ,
nil,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
El segundo hilo con solo acceso de lectura abre el mismo archivo:
FileHandle := CreateFile(
PCHar(FileName),
GENERIC_READ,
FILE_SHARE_READ + FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
No probé si funciona con ...
FILE_ATTRIBUTE_TEMPORARY,
FILE_FLAG_DELETE_ON_CLOSE
atributos ...
Necesito acceder a un archivo al mismo tiempo con múltiples hilos. Esto debe hacerse al mismo tiempo, sin serialización de subprocesos por razones de rendimiento.
El archivo en particular se ha creado con el atributo de archivo ''temporal'' que alienta a Windows a mantener el archivo en la memoria caché del sistema. Esto significa que la mayoría de las veces el archivo leído no se acerca al disco, pero leerá la parte del archivo del caché del sistema.
Ser capaz de acceder simultáneamente a este archivo mejorará significativamente el rendimiento de ciertos algoritmos en mi código.
Entonces, hay dos preguntas aquí:
- ¿Es posible que Windows acceda simultáneamente al mismo archivo desde diferentes subprocesos?
- Si es así, ¿cómo proporcionas esta habilidad? Intenté crear el archivo temporal y abrir nuevamente el archivo para proporcionar dos identificadores de archivo, pero el segundo abrir no funciona.
Aquí está la creación:
FFileSystem := CreateFile(PChar(FFileName),
GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE,
nil,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL OR
FILE_FLAG_RANDOM_ACCESS OR
FILE_ATTRIBUTE_TEMPORARY OR
FILE_FLAG_DELETE_ON_CLOSE,
0);
Aquí está el segundo abierto:
FFileSystem2 := CreateFile(PChar(FFileName),
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL OR
FILE_FLAG_RANDOM_ACCESS OR
FILE_ATTRIBUTE_TEMPORARY OR
FILE_FLAG_DELETE_ON_CLOSE,
0);
Probé varias combinaciones de banderas sin éxito hasta el momento. El segundo archivo abierto siempre falla, con mensajes que indican que no se puede acceder al archivo porque otro proceso lo está utilizando.
Editar:
OK, algo más de información (esperaba no perderme entre la maleza aquí ...)
El proceso en cuestión es un proceso de servidor Win32 que se ejecuta en WinXP 64. Mantiene grandes bases de datos espaciales y desea mantener la mayor cantidad posible de la base de datos espaciales en la memoria en una estructura de caché L1 / L2. L1 ya existe. L2 existe como un archivo ''temporal'' que se queda en la memoria caché del sistema de Windows (es un truco bastante sucio, pero supera las limitaciones de la memoria win32). Win64 significa que puedo tener mucha memoria utilizada por la memoria caché del sistema para que la memoria utilizada para contener la memoria caché L2 cuente hacia la memoria de proceso.
Múltiples (potencialmente muchos) subprocesos desean acceder concurrentemente a la información contenida en la caché L2. Actualmente, el acceso se serializa, lo que significa que un hilo obtiene para leer sus datos mientras que la mayoría (o el resto) de los hilos están bloqueados hasta que se complete esa operación.
El archivo de caché L2 se escribe, pero estoy feliz de serializar / intercalar en serie las operaciones de tipo de lectura y escritura, siempre que pueda realizar lecturas concurrentes.
Soy consciente de que hay desagradables problemas de simultaneidad de hilos, y soy consciente de que hay docenas de maneras de despellejar a este gato en otros contextos. Tengo este contexto particular, y estoy tratando de determinar si hay una manera de permitir el acceso simultáneo a la lectura de hilos dentro del archivo y dentro del mismo proceso.
Otro enfoque que he considerado sería dividir el caché L2 en múltiples archivos temporales, donde cada archivo serializa el acceso al hilo de la manera en que lo hace el único archivo de caché L2 actual.
Y sí, este enfoque algo desesperado es porque Delphi de 64 bits no estará con nosotros en el futuro cercano :-(
Gracias, Raymond.
Necesito acceder a un archivo al mismo tiempo con múltiples hilos. Esto debe hacerse al mismo tiempo, sin serialización de subprocesos por razones de rendimiento.
O no necesita usar el mismo archivo dentro de diferentes hilos, o necesita algún tipo de serialización.
De lo contrario, te estás preparando para un dolor de cabeza en el futuro.
Actualización # 2
Escribí algunos proyectos de prueba en C para tratar de resolver esto, aunque Rob Kennedy me golpeó con la respuesta mientras yo estaba fuera. Ambas condiciones son posibles, incluido el proceso cruzado, como lo describe. Aquí hay un enlace si alguien más quisiera ver esto en acción.
SharedFileTests.zip (VS2005 C ++ Solution) @ meklarian.com
Hay tres proyectos:
InProcessThreadShareTest - Probar un hilo de creador y cliente.
InProcessThreadShareTest.cpp Snippet @ gist.github
SharedFileHost: crea un host que se ejecuta durante 1 minuto y actualiza un archivo.
SharedFileClient: cree un cliente que se ejecute durante 30 segundos y sondee un archivo.
SharedFileHost.cpp y SharedFileClient.cpp Snippet @ gist.github
Todos estos proyectos asumen que la ubicación C: / data / tmp / sharetest.txt se puede crear y escribir.
Actualizar
Dado su escenario, parece que necesita una gran cantidad de memoria. En lugar de jugar con la memoria caché del sistema, puede usar AWE para tener acceso a más de 4 Gb de memoria, aunque necesitará asignar porciones a la vez. Esto debería cubrir su escenario L2 ya que desea asegurarse de que se use la memoria física.
Address Windowing Extensions @ MSDN
Use AllocateUserPhysicalPages y VirtualAlloc para reservar memoria.
Función AllocateUserPhysicalPages (Windows) @ MSDN
Función VirtualAlloc (Windows) @ MSDN
Inicial
Dado que está utilizando el indicador FILE_FLAG_DELETE_ON_CLOSE, ¿hay alguna razón por la que no considere utilizar un archivo mapeado en memoria?
Administrar archivos asignados en memoria en Win32 @ MSDN
Según lo que veo en sus declaraciones CreateFile, parece que desea compartir datos entre subprocesos o entre procesos, con respecto a tener el mismo archivo presente mientras se abren las sesiones. Un archivo mapeado de memoria le permite usar el mismo nombre de archivo lógico en todas las sesiones. Otro beneficio es que puede asignar vistas y bloquear partes del archivo asignado con seguridad en todas las sesiones. Si tiene un servidor estricto con escenario N-client, debería ser fácil de implementar. Si tiene un caso en el que un cliente puede ser el servidor de apertura, puede considerar utilizar algún otro mecanismo para asegurarse de que solo un cliente inicie primero el archivo de servicio (a través de un mutex global, quizás).
Si solo necesita una transmisión de datos en un solo sentido, quizás podría usar conductos con nombre.
(editar) Esto es mejor para 1 servidor a 1 cliente.
Sí, es posible que un programa abra el mismo archivo varias veces desde diferentes subprocesos. Sin embargo, querrá evitar leer el archivo al mismo tiempo que escribe. Puede usar TMultiReadExclusiveWriteSynchronizer
para controlar el acceso al archivo completo. Está menos serializado que, por ejemplo, una sección crítica. Para un control más granular, eche un vistazo a LockFileEx
para controlar el acceso a regiones específicas del archivo a medida que lo necesite. Al escribir, solicite un candado exclusivo; al leer, un bloqueo compartido.
En cuanto al código que ha publicado, al especificar File_Share_Write
en los indicadores de compartición iniciales, todas las operaciones abiertas posteriores también deben compartir el archivo para la escritura. Citando de la documentación :
Si no se especifica este indicador, pero el archivo o dispositivo se ha abierto para acceso de escritura o tiene una asignación de archivos con acceso de escritura, la función falla.
Su segunda solicitud abierta decía que no quería que se le permitiera a nadie escribir en el archivo mientras ese identificador permanecía abierto. Como ya existía otro identificador abierto que permitía escribir, no se pudo cumplir la segunda solicitud. GetLastError
debería haber devuelto 32, que es Error_Sharing_Violation
, exactamente lo que la documentación dice que debería suceder.
Especificar File_Flag_Delete_On_Close
significa que todas las solicitudes abiertas posteriores deben compartir el archivo para su eliminación. La documentación nuevamente:
Las solicitudes abiertas posteriores para el archivo fallan, a menos que se especifique el modo de compartir
FILE_SHARE_DELETE
.
Luego, dado que la segunda solicitud abierta comparte el archivo para su eliminación, todos los demás identificadores abiertos también deben haberlo compartido para su eliminación. La documentación:
Si hay identificadores abiertos existentes en un archivo, la llamada falla a menos que todos se hayan abierto con el modo de compartir
FILE_SHARE_DELETE
.
En resumidas cuentas, todos comparten o no comparten nada.
FFileSystem := CreateFile(PChar(FFileName),
Generic_Read or Generic_Write
File_Share_Read or File_Share_Write or File_Share_Delete,
nil,
Create_Always,
File_Attribute_Normal or File_Flag_Random_Access
or File_Attribute_Temporary or File_Flag_Delete_On_Close,
0);
FFileSystem2 := CreateFile(PChar(FFileName),
Generic_Read,
File_Share_Read or File_Share_Write or File_Share_Delete,
nil,
Open_Existing,
File_Attribute_Normal or File_Flag_Random_Access
or File_Attribute_Temporary or File_Flag_Delete_On_Close,
0);
En otras palabras, todos los parámetros son iguales excepto para el quinto.
Estas reglas se aplican a dos intentos de abrir en el mismo subproceso así como a intentos de diferentes subprocesos.