"Write a program using two threads such that one writes even numbers in increasing order and the other odd numbers in incresing order with respect to a certain threashold."
For instance, given 10 I would like to have as output
T1-0
T2-1
T1-2
T2-3
...
T1-8
T2-9
I think an event object should be used in order to alternate between the print of a thread with the other, but I do not know how to implement it in order to make it work, since I think I have not fully grasped the tools to work with threads, yet. I leave here my faulty code for the task
import threading
e = threading.Event()
def even(n):
if e.isSet() == False:
for i in range(0,n,+2):
e.set()
print(i)
e.clear()
e.wait()
def odd(n):
for i in range(1,n,+2):
e.wait()
print(i)
e.set()
t1 = threading.Thread(target = odd, args=(10,))
t2 = threading.Thread(target = even, args=(10,))
t1.start()
t2.start()
t1.join()
t2.join()
import threading
import time
def thread_function(name,max,y):
print(name,y)
time.sleep(0.1)
for i in range(int(max/2)):
time.sleep(0.3)
y= y + 2
print(name,y)
n = input("Input an integer \n")
n = int(n)
p=0
# Create thread
mt1 = threading.Thread(target=thread_function, args=("T-Even",n,p))
mt2 = threading.Thread(target=thread_function, args=("T-Odd",n,p+1))
# Start thread
mt1.start()
time.sleep(0.1)
mt2.start()
mt1.join()
Related
I want to use threading package to calculate the square of num and my code like,
import threading
def my_squr(num): #if this function take long time to run
print(num*num)
return num*num
if __name__ == "__main__":
l1 = [1,3,5,7,11,13,15,17]
for i, item in enumerate(l1):
if i % 3 == 0:
t1 = threading.Thread(target=my_squr, args=(item,))
t1.start()
t1.join()
elif i % 3 == 1:
t2 = threading.Thread(target=my_squr, args=(item,))
t2.start()
t2.join()
else:
t3 = threading.Thread(target=my_squr, args=(item,))
t3.start()
t3.join()
# t1.join()
# t2.join()
# t3.join()
print("Done")
However, I am confused about where should I put the join() method.Although, they both get same answer, I guess there are some differeces between them.
If you immediately join after started an thread, it means that wait until it executes. However, this isn't different than calling function normally inside main thread. Assume that functions works takes a bit of time and you need to process them at the same time.
Then you can start them and uncomment joins.
This is your current code snippet workflow
->Create thread x and start
->wait for finish of thread x
->Create thread y and start
->wait for finish of thread y
... and so on.
However if you change comments of joins this is new workflow
->Create thread x and start
->Create thread y and start
->Create thread z and start
...
at the end
->wait thread x to finish
->wait thread y to finish
...
So here even when you are waiting to finish X, your other threads like y and z still processing whatever you are doing inside.
EDIT:
You should remove the joins where right after the start and uncomment threads that are been in the end. That would be a more appropriate. Also, as processors are fast enough to complete simple math just in a millisecond, you will not experience any difference.
Where u should use the joins is completely dependent on your program.
For your situation using at the end probably would be the best.
However, assume you will have another thread called X_2 that will use result of thread X_1. Then before creating thread X_2, you should join thread X_1.
You could construct a list of the threads then join them all once your loop terminates:
import threading
def my_squr(num): #if this function take long time to run
print(num*num)
return num*num
if __name__ == "__main__":
threads = []
l1 = [1,3,5,7,11,13,15,17]
for i, item in enumerate(l1):
if i % 3 == 0:
t1 = threading.Thread(target=my_squr, args=(item,))
t1.start()
threads.append(t1)
elif i % 3 == 1:
t2 = threading.Thread(target=my_squr, args=(item,))
t2.start()
threads.append(t2)
else:
t3 = threading.Thread(target=my_squr, args=(item,))
t3.start()
threads.append(t3)
for thread in threads:
thread.join()
print("Done")
Join simply stops the application from ending before the thread completes.
So you want to join threads AFTER they have started.
import threading
def my_squr(num): #if this function take long time to run
print(num*num)
return num*num
if __name__ == "__main__":
threads = list()
l1 = [1,3,5,7,11,13,15,17]
for i, item in enumerate(l1):
if i % 3 == 0:
t1 = threading.Thread(target=my_squr, args=(item,))
threads.append(t1)
t1.start()
elif i % 3 == 1:
t2 = threading.Thread(target=my_squr, args=(item,))
threads.append(t2)
t2.start()
else:
t3 = threading.Thread(target=my_squr, args=(item,))
threads.append(t3)
t3.start()
for t in threads:
t,join()
print("Done")
i used multiprocessing but i don't know how to do it
the logic : a variable sign is equal to 0, with a function called timer count 20 seconds and each second check if sign is equal to 1 then it'll print something and breaks the loop, at the same time with a function called waiting waits for an input from another library as example "discord" or "socket" so if the input is equal to my key flip the variable sign to 1 and that affects the first function timer
import multiprocessing
from time import sleep
sign = 0
def timer():
for s in range(20):
if sign == 1: # if the input is equal to the secret key then break the timer
print("Yes!")
break
else:
sleep(1) #if not then continue timing
def waiting():
# maybe it waits for an input or a message from "discord or whatsapp"
if message == "secret_key":
sign = 1
p1 = multiprocessing.Process(target=timer)
p2 = multiprocessing.Process(target=waiting)
p1.start()
p2.start()
I mentioned it above in a comment, but here is how you would use an event
import time
import multiprocessing as mp
def timer(exit_event):
for s in range(20):
if exit_event.is_set():
print("Yes!")
break
else:
time.sleep(1) #if not then continue timing
def waiting(exit_event):
# maybe it waits for an input or a message from "discord or whatsapp"
time.sleep(5)
exit_event.set()
if __name__ == '__main__':
exit_event = mp.Event()
p1 = mp.Process(target=timer, args=(exit_event,))
p2 = mp.Process(target=waiting, args=(exit_event,))
p1.start()
p2.start()
p1.join()
p2.join()
However the real way to use an Event is to just to wait() for it to become true. No need for a sleep loop.
def timer(exit_event):
if exit_event.wait(timeout=20)
# returns True if the event is True. False if timed out
print("Yes!")
I have made a thread that is supposed to show the seconds passing. Unfortunately, when I use getstr from the curses module the whole script stops, including the thread. I have to use a thread lock to stop random characters being printed out because of overlapping orders.
Any suggestions on how to fix this or an alternative would be great!
In the below example window and window2 are already set-up...
lock = threaing.Lock()
def main_function():
#starts thread
t1 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
The problem with my code
I figured out the problem with my code. You can't run a thread inside a thread for some reason and I originally had my main function called to be considered a thread. I guess I should have stated this in my question. Sorry
There is probably a way to run a thread in a thread, but this did not work for me.
My Updated Code
lock = threading.Lock()
def call_threads():
t1 = threading.Thread(target=main_function,args=(window1,))
t1.start()
t2 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
def main_function(window1):
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
If there is anything else that may have caused this error, please comment it!
I am trying to figure out how in python one would declare a specific variable to be locked so that only one thread may access it at a time to avoid race conditions. If I have two threads constantly updating a variable via queues, but I am also updating the variable manually in main, what would be the right way to declare that variable a shared resource by all threads so that only one may access it at a time between the threads being run and main?
I wrote a little example code to show what I mean.
import time
from random import randint
from threading import Thread
from queue import Queue
# Add the amount by random number from 1 - 3 every second
def producer(queue, amount):
while True:
time.sleep(1)
amount[0] += randint(1, 3)
queue.put(amount)
# Subtract the amount by random number from 1 - 3 every second
def consumer(queue, amount):
while True:
item = queue.get()
amount[0] -= randint(1, 3)
queue.task_done()
amount = [10]
queue = Queue()
t1 = Thread(target=producer, args=(queue, amount,))
t2 = Thread(target=consumer, args=(queue, amount,))
t1.start()
t2.start()
while True:
n = input("Type a number or q: ")
if n == 'q':
break
else:
# Here is where I am confused about how to declare the amount a
# shared resource and lock it in a way that the queues would also
# adhere to
amount[0] += int(n)
print("amount is now: {}".format(amount[0]))
t1.join()
t2.join()
It is important to lock the variable when you are updating the value of it. so in your case indeed you require locking mechanism.
How to lock:
create a threading.Lock object which will help you lock and release the block of code.
acquire : to lock the code block. only one thread can enter in this block. other thread will wait until it is released.
release : to release the acquired lock.
In your case:
import time
from random import randint
from threading import Thread,Lock
from queue import Queue
# Add the amount by random number from 1 - 3 every second
def producer(queue, amount,lock):
while True:
time.sleep(1)
lock.acquire()
amount[0] += randint(1, 3)
queue.put(amount)
lock.release()
# Subtract the amount by random number from 1 - 3 every second
def consumer(queue, amount,lock):
while True:
lock.acquire()
item = queue.get()
amount[0] -= randint(1, 3)
queue.task_done()
lock.release()
amount = [10]
lock = Lock()
queue = Queue()
t1 = Thread(target=producer, args=(queue, amount,lock))
t2 = Thread(target=consumer, args=(queue, amount,lock))
t1.start()
t2.start()
...
I'm quite new to Python threading, and still can't make it working properly. I do not understand why, but threads are executed consequently and not in a parallel.
Could anyone please advice, what is incorrect in the code (I simplified it as much as I can to get it closer to the examples, but it doesn't work as expected):
import threading, time
def func1():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
print(str(time.ctime(time.time())) + " script started")
t1 = threading.Thread(target = func1(), name = " 1")
t2 = threading.Thread(target = func2(), name = " 2")
t1.start()
t2.start()
t1.join()
t2.join()
print (str(time.ctime(time.time())) + " over")
In console output I see that the second thread only starts when the first one is finished. I've tried to make threads daemonic, remove .join() lines, but still no luck.
I want to indicate the fact that a threading.Lock object and condition synchronization objects they define are used with the "with statement," because they support the context management protocol:
lock = threading.Lock() # After: import threading
with lock:
# critical section of code
...access shared resources...
Here, the context management machinery guarantees that the lock is automatically acquired before the block is executed and released once the block is complete, regardless of exception outcomes.
Therefore, the suggested solution above by Vincent seems to be addressing a more complex problem, one that deals with placing a lock on shared common resources, stopping any other thread that tries to access the resource in its tracks (in fact, stopping any thread that attempts to acquire the same lock). Notes: A threading.Lock has two states: locked and unlocked, and it is created in the unlocked state. In the following, for example, as only one thread can update the global variable "count":
import threading, time
count = 0
def adder(addlock): # shared lock object passed in
global count
with addlock:
count = count + 1 # auto acquire/release around stmt
time.sleep(0.5)
with addlock:
count = count + 1 # only 1 thread updating at any time
addlock = threading.Lock()
threads = []
for i in range(100):
thread = threading.Thread(target=adder, args=(addlock,))
thread.start()
threads.append(thread)
for thread in threads: thread.join()
print(count)
I'd suggest another solution using multiprocessing since your two parallel functions are basically two separate processes that don't need to access any shared resources.
from multiprocessing import Process
import time
def func1():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
if __name__ == '__main__':
print(str(time.ctime(time.time())) + " script started")
p1 = Process(target=func1)
p1.start()
p2 = Process(target=func2)
p2.start()
p1.join()
p2.join()
print (str(time.ctime(time.time())) + " over")
You're calling your targets (target=func1()). Instead do as follows:
t1 = threading.Thread(target=func1, name = "1")
t2 = threading.Thread(target=func2, name = "2")
EDIT: This is how you lock your prints :
import threading, time
def func1(lock):
for j in range (10):
with lock:
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2(lock):
for j in range (10):
with lock:
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
lock = threading.Lock()
t1 = threading.Thread(target = func1, name = " 1", args=(lock,))
t2 = threading.Thread(target = func2, name = " 2", args=(lock,))