Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"WindowsError: Access is denied" on calling Process.terminate

I enforce a timeout for a block of code using the multiprocessing module. It appears that with certain sized inputs, the following error is raised:

WindowsError: [Error 5] Access is denied

I can replicate this error with the following code. Note that the code completes with '467,912,040' but not with '517,912,040'.

import multiprocessing, Queue

def wrapper(queue, lst):
    lst.append(1)
    queue.put(lst)
    queue.close()

def timeout(timeout, lst):
    q = multiprocessing.Queue(1)
    proc = multiprocessing.Process(target=wrapper, args=(q, lst))
    proc.start()
    try:
        result = q.get(True, timeout)
    except Queue.Empty:
        return None
    finally:
        proc.terminate()
    return result

if __name__ == "__main__":
    # lst = [0]*417912040 # this works fine
    # lst = [0]*467912040 # this works fine
    lst = [0] * 517912040 # this does not
    print "List length:",len(lst)
    timeout(60*30, lst)

The output (including error):

List length: 517912040

Traceback (most recent call last):
  File ".\multiprocessing_error.py", line 29, in <module>
    print "List length:",len(lst)
  File ".\multiprocessing_error.py", line 21, in timeout
    proc.terminate()
  File "C:\Python27\lib\multiprocessing\process.py", line 137, in terminate
    self._popen.terminate()
  File "C:\Python27\lib\multiprocessing\forking.py", line 306, in terminate
    _subprocess.TerminateProcess(int(self._handle), TERMINATE)
WindowsError: [Error 5] Access is denied

Am I not permitted to terminate a Process of a certain size?

I am using Python 2.7 on Windows 7 (64bit).

like image 393
David C Avatar asked Jun 12 '13 22:06

David C


1 Answers

While I am still uncertain regarding the precise cause of the problem, I have some additional observations as well as a workaround.

Workaround.

Adding a try-except block in the finally clause.

finally:
    try:
        proc.terminate()
    except WindowsError:
        pass

This also seems to be the solution arrived at in a related (?) issue posted here on GitHub (you may have to scroll down a bit).

Observations.

  1. This error is dependent on the size of the object passed to the Process/Queue, but it is not related to the execution of the Process itself. In the OP, the Process completes before the timeout expires.
  2. proc.is_alive returns True before and after the execution of proc.terminate() (which then throws the WindowsError). A second or two later, proc.is_alive() returns False and a second call to proc.terminate() succeeds.
  3. Forcing the main thread to sleep time.sleep(1) in the finally block also prevents the throwing of the WindowsError. Thanks, @tdelaney's comment in the OP.
  4. My best guess is that proc is in the process of freeing memory (?, or something comparable) while being killed by the OS (having completed execution) when the call to proc.terminate() attempts to kill it again.
like image 61
David C Avatar answered Oct 30 '22 07:10

David C