2009-06-04 6 views
11

En utilisant le multitraitement sur les fenêtres, il semble que tous les descripteurs de fichiers ouverts sont hérités par des processus engendrés. Cela a l'effet secondaire désagréable de les verrouiller.Empêcher l'héritage du descripteur de fichiers dans la librairie multitraitement

Je suis intéressé soit:
1) Prévenir l'héritage
2) un moyen de libérer le fichier du processus donné naissance à

Consultez le code suivant qui fonctionne très bien sur Mac OS X, mais se bloque sur les fenêtres à os.rename

from multiprocessing import Process 
import os 

kFileA = "a.txt" 
kFileB = "b.txt" 

def emptyProcess(): 
    while 1: 
     pass 

def main(): 
    # Open a file and write a message 
    testFile = open(kFileA, 'a') 
    testFile.write("Message One\n") 

    # Spawn a process 
    p = Process(target=emptyProcess) 
    p.start() 

    # Close the file 
    testFile.close() 

    # This will crash 
    # WindowsError: [Error 32] The process cannot access the file 
    #    because it is being used by another process 
    os.rename(kFileA, kFileB) 

    testFile = open(kFileA, 'a') 
    testFile.write("Message Two\n") 
    testFile.close() 

    p.terminate() 


if __name__ == "__main__": 
    main() 

Répondre

0

Après avoir ouvert un descripteur de fichier, vous pouvez utiliser la fonction SetHandleInformation() pour enlever le drapeau HANDLE_FLAG_INHERIT.

+0

Comment obtenir le handle de fichier à partir de quelque chose créé avec open(), pas os.open()? – 14256424

1

Je ne sais pas sur le multitraitement le module, mais avec le module subprocess vous pouvez demander à ne pas hériter des descripteurs de fichier:

If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (Unix only). Or, on Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.

Sinon, vous pouvez fermer tous les descripteurs de fichiers dans votre processus d'enfant avec os.closerange

Close all file descriptors from fd_low (inclusive) to fd_high (exclusive), ignoring errors. Availability: Unix, Windows.

+2

Je suis conscient du drapeau de sous-processus, mais je demande spécifiquement au sujet du module multi-traitement. De plus, si nous avons un autre tube ou un autre fichier dont nous voulons hériter, le drapeau de close_fds est un peu lourd. – 14256424

+0

@vilalian Dans le cas où vous souhaitez conserver des descripteurs de fichiers hérités, vous devez transmettre ces informations au sous-processus afin qu'il sache quel (s) descripteur (s) de fichier ne doit pas fermer. Il n'y a pas d'autre chemin. – lothar

4

la méthode fileno() renvoie le numéro de fichier assigné par la bibliothèque d'exécution. Compte tenu du numéro de fichier, vous pouvez ensuite appeler msvcrt.get_osfhandle() pour obtenir le handle de fichier Win32. Utilisez cette poignée dans l'appel à SetHandleInformation. Donc, quelque chose comme ce qui suit travailler:

win32api.SetHandleInformation(
    msvcrt.get_osfhandle(testFile.fileno()), 
    win32api.HANDLE_FLAG_INHERIT, 
    0) 

Je ne suis pas certain de l'utilisation exacte du module win32api, mais cela devrait aider à combler l'écart entre un objet fichier Python et une poignée Win32.

0

J'ai rencontré ce problème lors de l'utilisation d'un journal rotatif et d'un multitraitement. Lorsque le processus parent essaie de tourner le journal, il échoue avec un

WindowsError: [Error 32] The process cannot access the file because it is being used by another process

basé sur quelques-unes des autres réponses, ce qui suit est une solution de travail en python 2.7 pour empêcher des gestionnaires de fichiers journaux de hérité

fd = logging.getLogger().handlers[0].stream.fileno() # The log handler file descriptor 
fh = msvcrt.get_osfhandle(fd) # The actual windows handler 
win32api.SetHandleInformation(fh, win32con.HANDLE_FLAG_INHERIT, 0) # Disable inheritance 

Veuillez noter que ce problème était quelque peu corrigé dans python 3.4. Pour plus d'informations, voir https://www.python.org/dev/peps/pep-0446/

Questions connexes