from __future__ import print_function
from threading import Semaphore, Lock, Thread
from time import sleep
from random import random
import argparse
from timeit import Timer
(THINKING, EATING) = (0, 1) #philosopher states
def left_fork(id):
return id
def right_fork(id):
return (id+1) % NUM_PHILOSOPHER
def right(id):
return (id+1) % NUM_PHILOSOPHER
def left(id):
return (id+NUM_PHILOSOPHER-1) % NUM_PHILOSOPHER
def get_fork(id):
global mutex
global tstate
global sem
mutex.acquire()
tstate[id] = 'hungry'
test(id)
mutex.release()
sem[id].acquire()
def put_fork(id):
global mutex
global tstate
global sem
mutex.acquire()
tstate[id] = 'thinking'
test(right(id))
test(left(id))
mutex.release()
def test(id):
global tstate
if tstate[id] == 'hungry' and tstate[left(id)] != 'eating' and tstate[right(id)] != 'eating':
tstate[id] = 'eating'
sem[id].release()
def philosophize_footman(id,meal):
global forks
global footman
state = THINKING
for i in range(meal):
sleep(random())
if(state == THINKING):
msg = "Philosopher " + str(id) + " is thinking."
#print(msg)
footman.acquire()
forks[right_fork(id)].acquire()
forks[left_fork(id)].acquire()
state = EATING
else:
msg = "Philosopher " + str(id) + " is eating."
#print(msg)
forks[right_fork(id)].release()
forks[left_fork(id)].release()
state = THINKING
footman.release()
print("Finish philosophize_footman")
def philosophize_lefthand(id,meal):
global forks
state = THINKING
for i in range(meal):
sleep(random())
if(state == THINKING):
#define the left hand user.
if(id == 3):
forks[left_fork(id)].acquire()
forks[right_fork(id)].acquire()
state = EATING
else:
forks[right_fork(id)].acquire()
forks[left_fork(id)].acquire()
state = EATING
else:
if(id == 3):
forks[left_fork(id)].release()
forks[right_fork(id)].release()
state == THINKING
else:
forks[right_fork(id)].release()
forks[left_fork(id)].release()
state == THINKING
print("Finish philosophize_lefthand")
def philosophize_Tanenbaum(id,meal):
for i in range(meal):
get_fork(id)
sleep(random())
put_fork(id)
print("Finish philosophize_Tanenbaum")
def run_c(numP,numM):
for m in range(numP):
phil1 = Thread(target = philosophize_Tanenbaum,args = (m,numM))
phil1.start()
def run_a():
global NUM_PHILOSOPHER
global MEAL
for i in range(NUM_PHILOSOPHER):
phil = Thread(target = philosophize_footman, args = (i,MEAL))
phil.start()
def run_b(numP,numM):
for n in range(numP):
phil2 = Thread(target = philosophize_lefthand, args = (n,numM))
phil2.start()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description = 'Philosopher dining')
parser.add_argument('--nphi','-n',
type = int,
default = 5,
help = 'add num_phi',
metavar = 'number of philosophers')
parser.add_argument('--meal','-m',
type = int,
default = 100,
help = 'number of meals',
metavar = 'meal')
args = parser.parse_args()
NUM_PHILOSOPHER = args.nphi #define number fo philosophers
MEAL = args.meal #define number of meals
forks = [Semaphore(1) for i in range(NUM_PHILOSOPHER)] #defines forks
sem = [Semaphore(0) for i in range(NUM_PHILOSOPHER)] #semaphores
footman = Semaphore(4) #limit the number of philosophers
mutex = Semaphore(1) #mutex
tstate = ['thinking'] * NUM_PHILOSOPHER #T-states
run_a()
# run_b(args.nphi,args.meal)
# run_c(args.nphi,args.meal)
timer = Timer(run_a)
print("Time:{:0.3f}s".format(timer. timeit(100)/100))
It is dinning philosopher problem solution by python. The code is listed above. I want to measure the running time of function run_a(). But when using timer, I found it doesn't work well. It prints the time result immediately(e.g 0.001s, but the code is still running.) So please help me with it! Thank you very much.
You need to wait for the threads to finish; call Thread.join() on each thread:
def run_a():
global NUM_PHILOSOPHER
global MEAL
threads = []
for i in range(NUM_PHILOSOPHER):
phil = Thread(target = philosophize_footman, args = (i,MEAL))
phil.start()
threads.append(phil)
for t in threads:
t.join()
The Thread.join() method blocks until the thread has completed, or you can specify a timeout.
Related
I would like to know if there is how to create two threads, one to ask some number and another to show this number typed in parallel.
from threading import Thread
global result
result = None
class OutPut(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
global result
if result is not None:
print('Number entered was: {}'.format(result))
class Write(Thread):
def __init__(self):
Thread.__init__(self);
def run(self):
global result
user_write = True
while user_write:
num = int(input('Enter a number? '))
result = num
if num == 0:
user_write = False
threadIO = Write()
threadOutPut = OutPut()
arrThread = [threadIO, threadOutPut]
for tH in arrThread:
tH.start()
for t in arrThread:
t.join()
print('===== THREADS OFF =====')
I was trying to do something with this code. The "thread" of asking until it works but showing what was typed doesn't.
I still could not pin down your exact requirements, but I think what you need is something like this...
import time
import readline
import thread
import sys
global num
num = None
def print_num():
while True:
time.sleep(5)
sys.stdout.write('\r'+' '*(len(readline.get_line_buffer())+2)+'\r')
global num
if num:
print("Writing ", num)
sys.stdout.write('Enter number > ' + readline.get_line_buffer())
sys.stdout.flush()
thread.Thread(target=print_num).start()
while True:
num = input('Enter number > ')
Here are some changes to your OutPut thread to print each result one time and also exit when 0 is input. The important part is that the OutPut thread must keep looping to check result, then reset result after printing it.
In your original code, you might consider putting a print at the end of OutPut's run function to see why the code doesn't work as you expected.
from threading import Thread
global result
result = None
class OutPut(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
global result
while True: # Loop to check the result
if result is not None:
print("Number entered was: {}".format(result))
if result == 0:
break # if result is 0, break the loop
result = None # reset the result to None, so we don't print the same result again
print("Thread finished")
class Write(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
global result
user_write = True
while user_write:
num = int(input("Enter a number? "))
result = num
if num == 0:
user_write = False
threadIO = Write()
threadOutPut = OutPut()
arrThread = [threadIO, threadOutPut]
for tH in arrThread:
tH.start()
for t in arrThread:
t.join()
print("===== THREADS OFF =====")
I have a program that is supposed to send a few data points over a serial connection to an arduino which will control some motors to move. I can send the control signals individually as well as by txt file which will run repeatedly until the file is complete. While running a txt file, I want to be able to exit the loop like a pause or stop button. I think the best way to do that is via a thread that I can close. I have never done any threading before and my rudimentary attempts have not worked. Here is the function that sends the file data.
def send_file():
# Global vars
global moto1pos
global motor2pos
# Set Ready value
global isready
# Get File location
program_file_name = file_list.get('active')
file_path = "/home/evan/Documents/bar_text_files/"
program_file = Path(file_path + program_file_name)
file = open(program_file)
pos1 = []
pos2 = []
speed1 = []
speed2 = []
accel1 = []
accel2 = []
for each in file:
vals = each.split()
pos1.append(int(vals[0]))
pos2.append(int(vals[1]))
speed1.append(int(vals[2]))
speed2.append(int(vals[3]))
accel1.append(int(vals[4]))
accel2.append(int(vals[5]))
# Send file values
try:
while isready == 1:
for i in range(len(pos1)):
print("Step: " + str(i+1))
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
try:
pos1time = abs(pos1[i]/speed1[i])
except:
pos1time = 0
try:
pos2time = abs(pos2[i]/speed2[i])
except:
pos2time = 0
time_array = (pos1time, pos2time)
time.sleep(max(time_array))
motor1pos = ser.readline()
motor2pos = ser.readline()
if i < (len(pos1)-1):
isready = ord(ser.read(1))
else:
isready = 0
except:
print("Error: data not sent. Check serial port is open")
Here is the threading command which I want the sendfile command to work from.
def thread():
try:
global isready
isready = 1
t = threading.Thread(name='sending_data', target=command)
t.start()
except:
print("Threading Error: you don't know what you are doing")
And here is the stop function I want the thread to be killed by:
def stop():
try:
global isready
isready = 0
t.kill()
except:
print("Error: thread wasn't killed")
I know you aren't supposed to kill a thread but the data isn't very important. Whats more important is to stop the motors before something breaks.
The button in tkinter is:
run_file_butt = tk.Button(master = file_frame, text = "Run File", command = thread)
When I click the button, the program runs but the stop function does nothing to stop the motion.
Question: run and kill a thread on a button press
There is no such a thing called .kill(....
Start making your def send_file(... a Thread object which is waiting your commands.
Note: As it stands, your inner while isready == 1: will not stop by using m.set_state('stop').
It's mandatory to start the Thread object inside:
if __name__ == '__main__':
m = MotorControl()
import threading, time
class MotorControl(threading.Thread):
def __init__(self):
super().__init__()
self.state = {'is_alive'}
self.start()
def set_state(self, state):
if state == 'stop':
state = 'idle'
self.state.add(state)
def terminate(self):
self.state = {}
# main function in a Thread object
def run(self):
# Here goes your initalisation
# ...
while 'is_alive' in self.state:
if 'start' in self.state:
isready = 1
while isready == 1:
# Here goes your activity
# Simulate activity
print('running')
time.sleep(2)
isready = 0
self.state = self.state - {'start'}
self.state.add('idle')
elif 'idle' in self.state:
print('idle')
time.sleep(1)
if __name__ == '__main__':
m = MotorControl()
time.sleep(2)
m.set_state('start')
time.sleep(3)
m.set_state('stop')
time.sleep(3)
m.set_state('start')
time.sleep(4)
m.terminate()
print('EXIT __main__')
Your tk.Button should look like:
tk.Button(text = "Run File", command = lambda:m.set_state('start'))
tk.Button(text = "Stop File", command = lambda:m.set_state('stop'))
tk.Button(text = "Terminate", command = m.terminate)
The answer I have gone with is simple due to my simple understanding of threading and unique circumstances with which I am using the threading. Instead of terminating the thread in a way I was hoping, I added another conditional statement to the sending line of the send_file function.
while isready == 1:
for i in range(len(pos1)):
if motorstop == False:
print("Step: " + str(i+1))
#data = struct.pack('!llllhhhhhhhh', pos1[i], pos2[i], pos3[i], pos4[i], speed1[i], speed2[i], speed3[i], speed[4], accel1[i], accel2[i], accel3[i], accel4[i])
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
else:
isready = 0
break
and I have updated my stop() func to the following:
def stop():
try:
global motorstop
global t
motorstop = True
t.join()
except:
print("Error: thread wasn't killed")
I'm not exactly sure how it works but it is much simpler than what was mentioned by #stovefl.
With this code, since the function is mostly just sleeping, it can run but it won't send any new information and then will .join() after the next iteration.
This question already has answers here:
Is there any way to kill a Thread?
(31 answers)
Closed 6 years ago.
i've got this code, how can I stop func2 from func1? something like Thread(target = func1).stop() doesn't work
import threading
from threading import Thread
def func1():
while True:
print 'working 1'
def func2():
while True:
print 'Working2'
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
It's better to ask your other thread to stop, using a message queue for instance.
import time
import threading
from threading import Thread
import Queue
q = Queue.Queue()
def func1():
while True:
try:
item = q.get(True, 1)
if item == 'quit':
print 'quitting'
break
except:
pass
print 'working 1'
def func2():
time.sleep(10)
q.put("quit")
while True:
time.sleep(1)
print 'Working2'
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
You cannot tell a thread to stop, you have to make it return in its target function
from threading import Thread
import Queue
q = Queue.Queue()
def thread_func():
while True:
# checking if done
try:
item = q.get(False)
if item == 'stop':
break # or return
except Queue.Empty:
pass
print 'working 1'
def stop():
q.put('stop')
if __name__ == '__main__':
Thread(target=thread_func).start()
# so some stuff
...
stop() # here you tell your thread to stop
# it will stop the next time it passes at (checking if done)
I have the following code which acts pretty strange.
class A:
def __init__(self):
self.lock = Lock()
self.process_list = []
self.event_list = []
def run(self):
self.process_list = []
counter = 0
n = 0
while (n<1000):
n += 1
print("in while again")
self.lock.acquire()
print('after acquired lock')
self.lock.release()
self.event_list.append(Event())
print('add event')
p = Process(target=workerEmulator().run,
args=(self.lock, self.event_list[counter]))
print('create process')
self.process_list.append(p)
print('add process')
self.event_list[counter].clear()
counter += 1
print("about to start process")
print("n="+str(n))
p.start()
print("new process started")
print(": main process, active_children: " + str(multiprocessing.active_children()))
del_list = [] # the list for storing index of the process/event to delete
for i in range(len(self.event_list)):
if (self.event_list[i].is_set()):
self.process_list[i].join()
print("one process finished, its exit code: " + str(self.process_list[i].exitcode))
print("this process is alived or not? " + str(self.process_list[i].is_alive()))
del_list.append(i)
del_list.sort(reverse=True)
for i in del_list:
del self.event_list[i]
del self.process_list[i]
counter -= 1
time.sleep(0.1)
for p in self.process_list:
p.join()
print("one process finished, its exit code: " + str(p.exitcode))
print("this process is alived or not? " + str(p.is_alive()))
class workerEmulator:
def __init__(self):
pass
def run(self, lock, event):
print("a new process")
self.lock = lock
self.event = event
time.sleep(20)
print("after sleep")
self.lock.acquire()
print("in lock")
self.lock.release()
self.event.set()
if __name__ == '__main__':
a = A()
a.run()
As I thought, every print statement should be executed 1000 times. However, it is never the case, there are always a few times missing, then if we look at n, I noticed that n will jump over some number, for example, ... n=798...n=799...n=801...n=802... (n=800 missing). I don't see why this happens, could someone help?
See Matt's comment, the problem is caused by child output intermingles with parent output.
I have the following sample code that I am trying to use the multiprocessing module on. The following statement had been working previously under other applications, but one process (which receives a very small amount of data just due to the breakup) finishes first and causes the program to finish. Could someone help me understand why this is not waiting for the others?
def mpProcessor(basePath, jsonData, num_procs = mp.cpu_count()):
manager = mp.Manager()
map = manager.dict()
procs = mp.Pool(processes = num_procs, maxtasksperchild = 1)
chunkSize = len(jsonData) / (num_procs)
dataChunk = [(i, i + chunkSize) for i in range(0, len(jsonData), chunkSize)]
count = 1
for i in dataChunk:
print 'test'
s, e = i
procs.apply_async(processJSON, args = (count, basePath, jsonData[s:e]))
count += 1
procs.close()
procs.join()
return map
def processJSON(proc, basePath, records):
print 'Spawning new process: %d' %os.getpid()
outDict = dict()
print len(records)
for i in range(len(records)):
valid = False
idx = 0
while valid == False:
jsonObject = json.loads(records[i][1])['results'][idx]
if jsonObject['kind'] == 'song':
valid = True
break
else:
idx += 1
tunesTrack = Track()
tunesTrack.setTrackId(jsonObject['trackId'])
print 'Finished processing %d records with process %d' %(len(records), os.getpid())
You seem to be reinventing the wheel.
What you are trying to do could be much more easily achieved by using an initializer with the pool and using map rather than apply_async. As it stands your code snippet is not runnable so I can't be sure what the actual problem is. However, the following should simplify your code and make it easier to debug.
import math
import multiprocessing as mp
def pool_init(basePath_):
global basePath, job_count
basePath = basePath_
job_count = 0
print 'Spawning new process: %d' %os.getpid()
def mpProcessor(basePath, jsonData, num_procs=mp.cpu_count()):
pool = mp.Pool(processes=num_procs, initializer=pool_init, initargs=(basePath,))
# could specify a chunksize, but multiprocessing works out the optimal chunksize
return pool.map(processJSON, jsonData)
# change processJSON to work with single records and
# remove proc and basePath args (as not needed)
def processJSON(record):
global job_count
print 'Starting job %d in process: %d' % (job_count, os.getpid())
valid = False
idx = 0
while valid == False:
jsonObject = json.loads(record[1])['results'][idx]
if jsonObject['kind'] == 'song':
valid = True
break
else:
idx += 1
tunesTrack = Track()
tunesTrack.setTrackId(jsonObject['trackId'])
print 'Finished processing job %d with process %d' % (job_count, os.getpid())
job_count += 1