-1

I need to use 3 threads to print array items sequentially using Python.

Each Thread will print one array item.

I need the threads to sleep for a random number of seconds and then print the item.

This function will be executed N times. This N value is given by the user.

The items must be printed on a specific order, which means I have to somehow block the other threads to execute while the previous one is not done. I've been trying a lot of different solutions but I can't figure out how to make it work.

I've tried to use Semaphores, Lock and Events but without success on the synchronization. In all cases it would print the sequence randomly, according to the time.sleep and not with the sequence itself. How can I block the thread from executing the function and check if the previous thread was finished in order to allow the sequence to work?

Which tool should I use to make it work? Any help is appreciated.

class myThread(threading.Thread):
def __init__(self, group=None, target=None, name=None,
             args=(), kwargs=None, verbose=None):
    super(myThread,self).__init__()
    self.target = target
    self.name = name
    return

def run(self):
    while True:
        if not q.empty():
            semaphore.acquire() 
            try:
                time_sleep = random.randrange(0,10) 
                print "thread " + self.name + ". Dormir por " + str(time_sleep) + " segundos"
                time.sleep(time_sleep)
                print cores[int(self.name)]
                if int(self.name) == len(cores) - 1:
                    item = q.get()
                    print 'Executou sequencia ' + str(item + 1) + ' vezes. Ainda irá executar ' + str(q.qsize()) + ' vezes'
                    e.set()
            finally:
                semaphore.release()
                if int(self.name) != len(cores) - 1:
                    e.wait()
    return

if __name__ == '__main__':
    for i in range(2):
        q.put(i)

    for i in range(3):
        t = myThread(name=i)
        t.start()
Jaqueline Passos
  • 1,301
  • 2
  • 24
  • 37
  • 1
    If you want this behavior, why are you using threads in the first place? Also, you say `I've been trying a lot` - show us your attempts and how they failed to meet your expectations. – That1Guy Oct 07 '16 at 20:08

2 Answers2

0

There are many, many approaches to this. A simple one is to use a shared Queue of numbers.

Each thread can sleep for however long it wants to, take a number from the queue when it wakes up, and print it. They will come out in the order they were pushed to the queue.

If your numbers are sequential, or can generated dynamically, you can also do it in constant-memory using a shared counter, as described in this answer.

Community
  • 1
  • 1
salezica
  • 74,081
  • 25
  • 105
  • 166
  • This won't solve the problem because if Thread 1 sleeps for 8 seconds and Thread 3 sleeps for 0 seconds, Thread 3 would print before Thread 1... not following the sequence. I've posted a piece of code in the question now too... I've used query to check the number of times que sequence was called and by getting one item if its the last Thread. – Jaqueline Passos Oct 07 '16 at 20:44
  • As I understood, the numbers have to printed in sequence, no matter what thread is running when. Isn't that right? – salezica Oct 11 '16 at 13:34
0

If you didn't care about order you could just use a lock to synchronize access. In this case, though, how about a list of events. Each thread gets its own event slot and hands it to the next event in the list when done. This scheme could be fancied up by returning a context manager so that you don't need to release explicitly.

import threading

class EventSlots(object):

    def __init__(self, num_slots):
        self.num_slots = num_slots
        self.events = [threading.Event() for _ in range(num_slots)]
        self.events[0].set()

    def wait_slot(self, slot_num):
        self.events[slot_num].wait()
        self.events[slot_num].clear()

    def release_slot(self, slot_num):
        self.events[(slot_num + 1) % self.num_slots].set()


def worker(event_slots, slot_num):
    for i in range(5):
        event_slots.wait_slot(slot_num)
        print('slot', slot_num, 'iteration', i)
        event_slots.release_slot(slot_num)


NUM = 3

slots = EventSlots(NUM)

threads = []

for slot in range(NUM):
    t = threading.Thread(target=worker, args=(slots, slot))
    t.start()
    threads.append(t)

for t in threads:
    t.join()
tdelaney
  • 73,364
  • 6
  • 83
  • 116