my python code goes like this:
def a():
...
...
subprocess.call()
...
...
def b():
...
...
and so on.
My task:
1) If subprocess.call() returns within 3 seconds, my execution should continue the moment subprocess.call() returns.
2) If subprocess.call() does not return within 3 seconds, the subprocess.call() should be terminated and my execution should continue after 3 seconds.
3) Until subprocess.call() returns or 3 seconds finishes, the further execution should not take place.
This can be done with threads but how?
Relevant part of the real code goes like this:
...
cmd = ["gcc", "-O2", srcname, "-o", execname];
p = subprocess.Popen(cmd,stderr=errfile)//compiling C program
...
...
inputfile=open(input,'w')
inputfile.write(scanf_elements)
inputfile.close()
inputfile=open(input,'r')
tempfile=open(temp,'w')
subprocess.call(["./"+execname,str(commandline_argument)],stdin=inputfile,stdout=tempfile); //executing C program
tempfile.close()
inputfile.close()
...
...
I am trying to compile and execute a C program using python.
When I am executing C program using subprocess.call() and suppose if the C program contains an infinite loop, then the subprocess.call() should be terminated after 3 seconds and the program should continue. I should be able to know whether the subprocess.call() was forcefully terminated or successfully executed so that I can accordingly print the message in the following code.
The back end gcc is of linux.
My task:
1) If subprocess.call() returns within 3 seconds, my
execution should continue the moment subprocess.call() returns.
2) If
subprocess.call() does not return within 3 seconds, the
subprocess.call() should be terminated and my execution should
continue after 3 seconds.
3) Until subprocess.call() returns or 3
seconds finishes, the further execution should not take place.
On *nix, you could use signal.alarm()-based solution:
import signal
import subprocess
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
raise Alarm
# start process
process = subprocess.Popen(*your_subprocess_call_args)
# set signal handler
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(3) # produce SIGALRM in 3 seconds
try:
process.wait() # wait for the process to finish
signal.alarm(0) # cancel alarm
except Alarm: # subprocess does not return within 3 seconds
process.terminate() # terminate subprocess
process.wait()
Here's a portable threading.Timer()-based solution:
import subprocess
import threading
# start process
process = subprocess.Popen(*your_subprocess_call_args)
# terminate process in 3 seconds
def terminate():
if process.poll() is None:
try:
process.terminate()
except EnvironmentError:
pass # ignore
timer = threading.Timer(3, terminate)
timer.start()
process.wait()
timer.cancel()
Finally the below code worked:
import subprocess
import threading
import time
def process_tree_kill(process_pid):
subprocess.call(['taskkill', '/F', '/T', '/PID', process_pid])
def main():
cmd = ["gcc", "-O2", "a.c", "-o", "a"];
p = subprocess.Popen(cmd)
p.wait()
print "Compiled"
start = time.time()
process = subprocess.Popen("a",shell=True)
print(str(process.pid))
# terminate process in timeout seconds
timeout = 3 # seconds
timer = threading.Timer(timeout, process_tree_kill,[str(process.pid)])
timer.start()
process.wait()
timer.cancel()
elapsed = (time.time() - start)
print elapsed
if __name__=="__main__":
main()
If you're willing to convert your call to a Popen constructor instead of call (same way you are running gcc), then one way to approach this is to wait 3 seconds, poll the subprocess, and then take action based on whether its returncode attribute is still None or not. Consider the following highly contrived example:
import sys
import time
import logging
import subprocess
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
if __name__ == '__main__':
logging.info('Main context started')
procCmd = 'sleep %d' % int(sys.argv[1])
proc = subprocess.Popen(procCmd.split())
time.sleep(3)
if proc.poll() is None:
logging.warning('Child process has not ended yet, terminating now')
proc.terminate()
else:
logging.info('Child process ended normally: return code = %s' % str(proc.returncode))
logging.info('Main context doing other things now')
time.sleep(5)
logging.info('Main context ended')
And this results in different logging output depending upon whether the child process completed within 3 seconds or not:
$ python parent.py 1
2015-01-18 07:00:56,639 INFO Main context started
2015-01-18 07:00:59,645 INFO Child process ended normally: return code = 0
2015-01-18 07:00:59,645 INFO Main context doing other things now
2015-01-18 07:01:04,651 INFO Main context ended
$ python parent.py 10
2015-01-18 07:01:05,951 INFO Main context started
2015-01-18 07:01:08,957 WARNING Child process has not ended yet, terminating now
2015-01-18 07:01:08,957 INFO Main context doing other things now
2015-01-18 07:01:13,962 INFO Main context ended
Note that this approach above will always wait 3 seconds even if the subprocess completes sooner than that. You could convert the above into something like a loop that continually polls the child process if you want different behavior - you'll just need to keep track of how much time has elapsed.
#!/usr/bin/python
import thread
import threading
import time
import subprocess
import os
ret=-1
def b(arg):
global ret
ret=subprocess.call(arg,shell=True);
thread.start_new_thread(b,("echo abcd",))
start = time.time()
while (not (ret == 0)) and ((time.time() - start)<=3):
pass
if (not (ret == 0)) :
print "failed"
elapsed = (time.time() - start)
print elapsed
thread.exit()
elif (ret == 0):#ran before 3 sec
print "successful"
elapsed = (time.time() - start)
print elapsed
I have written the above code which is working and satisfying all my contstraints.
The link https://docs.python.org/2/library/thread.html says:
thread.exit()
Raise the SystemExit exception. When not caught, this will cause the thread to exit silently.
So I suppose there should be no problem of orphan processes, blocked resources, etc. Please suggest.
Related
cls
do
keyed$=inkey$
loop until keyed$<>""
print"the hello world"
end
so in this program as you have seen until a press a key in the statement "keyed$=inkey$" the program wont display the hello world. so i want such a statement or program which will exit the loop in certain time. so the program will wait for 4 second and if users press the key before than that it will go to next line and even if the user wont press any key then program will move to next line in 4 second. please help me!!!
You can use the SLEEP statement:
PRINT "Press a key within 4 seconds to win!"
' Wait 4 seconds or until a key is pressed.
SLEEP 4
' Collect the key pressed, if any.
keyed$ = INKEY$
IF keyed$ <> "" THEN
PRINT "You WON by typing: "; keyed$
ELSE
PRINT "You LOST!"
END IF
Note that certain keys such as the arrow keys are considered "extended" keys. The first character of keyed$ will be equal to CHR$(0) to tell you that an extended key was detected, and the second character will allow you to determine which key it was. You can find more information on the QB64 wiki about those "two byte codes" if you need to handle them. For such keys, the code above won't work so well, as shown below when I press the Up arrow key (CHR$(0) + CHR$(&H48)):
Press a key within 4 seconds to win!
You WON by typing: H
^note the extra space for CHR$(0)
Edit
You can use this instead of a loop to do what you want:
' Wait 4 seconds for a key to be pressed.
SLEEP 4
' If a key was not pressed in 4 seconds, keyed$ = "".
keyed$ = INKEY$
IF keyed$ = "" THEN PRINT "Timeout (no key pressed)"
PRINT "the hello world"
In other words, no loop is needed to detect whether a key was pressed if you use the SLEEP statement and immediately use the INKEY$ function afterward.
If you still prefer a timer-based solution with a loop, then you can use a few extra variables, an additional loop condition, and the TIMER function, which returns the number of seconds elapsed since midnight. The following does the same thing as the SLEEP method above:
maxWait = 4
startTime = TIMER
DO
' Detect a key press.
keyed$ = INKEY$
' Fix the start time if the loop started before midnight
' and the current time is after midnight.
IF startTime > TIMER THEN startTime = startTime - 86400
' Loop until a key is pressed or maxWait seconds have elapsed.
LOOP UNTIL keyed$ <> "" OR startTime + maxWait < TIMER
' If a key was not pressed in 4 seconds, keyed$ = "".
IF keyed$ = "" THEN PRINT "Timeout (no key pressed)"
PRINT "the hello world"
The advantage to this more complex option is the fact that you can do other things in the loop while waiting for a key press. Of course, there is a slight problem. If you're doing too much, the key press will be detected late because INKEY$ won't be called right when the key is pressed. For example:
maxWait = 4
startTime = TIMER
DO
' Do some work.
x = 0
FOR i = 1 TO 1000000
x = x + 1
NEXT i
' Detect a key press and exit the loop if one is detected.
keyed$ = INKEY$
' Fix the start time if the loop started before midnight
' and the current time is after midnight.
IF startTime > TIMER THEN startTime = startTime - 86400
' Loop until a key is pressed or maxWait seconds have elapsed.
LOOP UNTIL keyed$ <> "" OR startTime + maxWait < TIMER
It's tricky to avoid the issue. One option is ON TIMER(n) as suggested by #MatthewWhited, except you can only use one timer event. This means you would need it to exit the loop after maxWait seconds rather than detect a key press, even if there is work occurring. Meanwhile, your key presses will still be detected noticeably later than desired. QB64 allows for the usage of multiple timers, allowing you to handle both. It also allows you to specify n with millisecond precision, unlike QBasic that only allows for 1-second precision at minimum. See ON TIMER(n) on the QB64 Wiki for more information about QB64's improvements to ON TIMER(n).
Since I don't know your usage case, I can't recommend one solution or another, based on the code you've provided.
I want to receive a string from an array using a variables' integer as the array index. But it is not working.
Attempt 1
; Suspended | 0 = No, 1 = Yes
global Suspended := 0
global SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
Pause::
Suspend
if suspended = 0 ; If script is not suspended
{
TrayTip, Paused, SuspendedMsg[Suspended], 3
Suspended++
} else ; If it is suspended
{
TrayTip, Activated, SuspendedMsg[Suspended], 3
Suspended--
}
return
Attempt #1 will just display the string "SuspendedMsg[Suspended]" because I don't know where to set the variable indicator %. Even if I set it to SuspendedMsg[%Suspended%] it will either display [1] or [0].
Attempt 2
; Suspended | 0 = No, 1 = Yes
global Suspended := 0
global SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
global SendSuspendMsg := SuspendedMsg[Suspended]
Pause::
Suspend
if suspended = 0 ; If script is not suspended
{
TrayTip, Paused, %SendSuspendMsg%, 3
Suspended++
} else ; If it is suspended
{
TrayTip, Activated, %SendSuspendMsg%, 3
Suspended--
}
return
Attempt #2 won't do as well, it doesn't even display any message. I tried fiddling arround with % inside the global SendSuspendMsg := SuspendedMsg[Suspended] variable but it won't do no good. Anyone care to help me out?
#Blauhim missed an important point, although his answer is mostly correct. First the Index in an Array when created like you did, always starts at 1, then proceeds to 2 etc, etc... So your code was flawed when you tried to use your Boolean variable to call to an index as a 0 Index does not exist (not to mention that you didn't force and Expression on that TrayTip Command).
; Set our variable to 1 why? Because we are going to use a Logical switch below.
Suspended := 1
; This was correct format and I left it, although I removed Global's as they are not needed
SuspendedMsg := ["The script has been paused.","The script has been re-activated."]
Pause::
; Suspend toggles each time it's called
Suspend
; Here we are toggling the value of our variable using !
; We started with a 1 so that it would be correctly
;Changed to a 0 for the code below.
suspended := !suspended
; Nothing changed here
if suspended = 0 ; If script is not suspended
{
; In order to pass an Array or Object or Expression to a Command you Force it
; using the a Percent Sign with a space on either side.
; Also note you were trying to use your Logical True/False 0 or 1 variable to
; itterate. This didn't work because Array's always start with an Index of 1.
; Below I've accounted for this by simply added a 1 to your suspended so it correctly
; points to the Index in our Array.
TrayTip, Paused, % SuspendedMsg[suspended + 1], 3
} else ; If it is suspended
{
TrayTip, Activated, % SuspendedMsg[suspended + 1], 3
}
return
Instead of TrayTip, Paused, SuspendedMsg[Suspended], 3 or TrayTip, Paused, SuspendedMsg[%Suspended%], 3, try
TrayTip, Paused, % SuspendedMsg[Suspended], 3
. TrayTip asks you for a
specify the message to display
which means as much as a String. So, variables names aren't handled as variables here, but as strings instead (as most of the times in commands). It would make sense to state TrayTip, Paused, %SuspendedMsg[%Suspended%]%, 3
, but you cannot nest variable's percent signs. So, we'll have to use the percent sign to force an expression:
Force an expression: An expression can be used in a parameter that does not directly support it (except OutputVar parameters) by preceding the expression with a percent sign and a space or tab. In [v1.1.21+], this prefix can be used in the InputVar parameters of all commands except the traditional IF commands (use If (expression) instead). This technique is often used to access arrays.
Concerning your second problem: I don't think Arrays can be declared like that, can they..? (but I'm not sure). Also see this short article. So I guess the problem lies within the 3rd line of your code, because the rest of it looks good to me
how do I keep the output to two decimal places
no decimal places:
import time
print ("60 SECOND TIMER")
run = input('click ENTER to run')
secs=0
while secs < 60:
print(60 - secs)
time.sleep(1)
secs = secs+1
two decimal places:
import time
print ("60 SECOND TIMER")
run = input('click ENTER to run')
secs=0
while secs < 60:
print(60 - secs)
time.sleep(0.01)
secs = secs+0.01
Quick note: two decimal places starts going mad (ends up with 8 or 9 decimal places
Use the round() function like this:
print(round(60 - secs, 2))
to output the remaining time to two decimal places.
Incidentally, printing it every 10 ms may be a bit optimistic considering that your display is probably only updated 60 times a second, i.e. at 16.67 ms intervals.
try time.sleep(.01 - timer() % .01), to lock the sleep with the timer(). Though it won't help if either time.sleep() or timer() do not support 10ms granularity. It may also depend on how Python interpreter switches between threads (GIL acquire/release) and OS scheduler (how busy the system is and how fast OS can switch between processes/threads).
To pause for a short duration, you could try a busy loop instead:
from time import monotonic as timer
deadline = timer() + .01
while timer() < deadline:
pass
For example, to do something every 10ms for a minute using time.sleep() would probably fail:
import time
from time import monotonic as timer
now = timer()
deadline = now + 60 # a minute
while now < deadline: # do something until the deadline
time.sleep(.01 - timer() % .01) # sleep until 10ms boundary
now = timer()
print("%.06f" % (deadline - now,))
but the solution based on a busy loop should be more precise:
import time
from time import monotonic as timer
dt = .01 # 10ms
time.sleep(dt - timer() % dt)
deadline = now = timer()
outer_deadline = now + 60 # a minute
while now < outer_deadline: # do something until the deadline
print("%.06f" % (outer_deadline - now,))
# pause until the next 10ms boundary
deadline += dt
while now < deadline:
now = timer()
Question
Basically, the title says it all! How do I stop execution of my hotkey via a hotkey?
How do I do so without closing the script?
How do I explicitly set a hotkey to take priority over a specific loop?
Explanation
I have a loop that executes several hundred times (code attached), and I would like to create a kill switch. I don't want to have to re-open the script if I stop it running, and I need to have lengthy sleeps, so I can fool with the mouse, as it is.
I'm looking at various pages, such as tutorial and break.
What I've tried
For example, should I name my loop somehow? Because Break takes no parameters, I'm thinking: there's no way to specify what to break.
Another example: should I add a hotkey into my loop to break? If so, how do I do that? Just throw ^!p:: into a nest under each hotkey? Or is there another way to add a hotkey to a hotkey (for example, with GetKeyState)?
Answer format
If possible, please show don't tell your answers, using the following code:
^!i::
{
Loop 1300
{
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 100, 600, 400
Sleep 1000
Send 1
Sleep 500
}
Return
}
^!o::
{
Loop 1323
{
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
Send 1
}
Return
}
If you want a controlled stop, i.e. at a certain point in the script, then you could use a hotkey to set a variable and test that variable in the script. When the variable has been set and the IF statement is true, you reset that variable and exit the loop. Otherwise, you could kill the script at a random point through the reload command. This way the script is closed, but immediately reopened.
^!i::
MyStopVariable:=0 ; Set the variable to 0
Loop 1300
{
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Sleep 500
}
Return
^!o::
MyStopVariable:=0 ; Set the variable to 0
Loop 1323
{
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send ^+{PrintScreen}
Sleep 1500
MouseClickDrag, left, 0, 200, 600, 400
Sleep 1000
If MyStopVariable
Exit ; Or Break if you want to finish something of after the loop
Send 1
}
Return
^!s:: ; Ctrl+Alt+s = stop
MyStopVariable:=1
Return
Alternatively, you could use your original code and add a reload.
^!s:: ; Ctrl+Alt+s = stop
Reload
Return
I have the following Erlang function which calls another function and waits
for 40 seconds and then prints something,
the problem is that when i try to run the program the it takes lot more time than
40 second for the receive statement to return to the Erlang shell.
What could be the cause of this issue?
reboot_node_return(Sc) ->
linux(Sc, "reboot -f"),
receive _ -> ok
after 40000 ->
io:format("successfull reboot:~n")
end.
-A
reboot_node_return(Sc) ->
linux(Sc, "reboot "),
receive _ -> ok
after 40000 ->
io:format("successfull reboot:~n")
end.