1

my code. it starts 2 threads with inner schedulers that print number every second

import threading
import time
from datetime import datetime

import schedule

_lock = threading.Lock()


def p(number):
    _lock.acquire()
    print(number, datetime.now())
    _lock.release()


def f(number):
    schedule.every(5).seconds.do(p, number)
    while True:
        schedule.run_pending()
        time.sleep(1)


thread = threading.Thread(target=f, args=(1,))
thread2 = threading.Thread(target=f, args=(2,))
thread.start()
thread2.start()

expected output

1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:22.821887
2 2020-03-25 22:07:22.821887
1 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093

actual output (see 4 instead of 2 prints at 17' and 3 instead of 2 prints at 27')

1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:22.821887
2 2020-03-25 22:07:22.821887
1 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093

I dont actually know why sometimes thread triggers function more than just once. Any idea what i do wrong ?

1 Answers1

2

You're having what's called a race condition. Two threads are trying to write to stdout (i.e. print) simultaneously, but the order they are able to get a hold of this resource depends on the scheduler's timing.

To solve the problem you need to introduce a way to synchronize their access, so when one thread tries to print something, the other has to wait until it finishes.

Modify your code like this:

import threading
# ...

_lock = threading.Lock()

def p(number):
    _lock.acquire()
    print(number, end='')
    _lock.release()

# ...

https://docs.python.org/3.8/library/threading.html#threading.Lock

abdusco
  • 9,700
  • 2
  • 27
  • 44