Martin
Martin

Reputation: 10888

Is this Python code thread safe?

import time
import threading

class test(threading.Thread):
    def __init__ (self):
      threading.Thread.__init__(self)
      self.doSkip = False
      self.count = 0

    def run(self):
      while self.count<9:
         self.work()

    def skip(self):
      self.doSkip = True

    def work(self):
      self.count+=1
      time.sleep(1)
      if(self.doSkip):
        print "skipped"
        self.doSkip = False
        return
      print self.count

t = test()
t.start()
while t.count<9:
  time.sleep(2)
  t.skip()

Upvotes: 2

Views: 1276

Answers (5)

John Fouhy
John Fouhy

Reputation: 42243

To elaborate on DanM's answer, conceivably this could happen:

  1. Thread 1: t.skip()
  2. Thread 2: if self.doSkip: print 'skipped'
  3. Thread 1: t.skip()
  4. Thread 2: self.doSkip = False
  5. etc.

In other words, while you might expect to see one "skipped" for every call to t.skip(), this sequence of events would violate that.

However, because of your sleep() calls, I think this sequence of events is actually impossible.

(unless your computer is running really slowly)

Upvotes: 0

DanM
DanM

Reputation: 2391

Whenever the test of a mutex boolean ( e.g. if(self.doSkip) ) is separate from the set of the mutex boolean you will probably have threading problems.

The rule is that your thread will get swapped out at the most inconvenient time. That is, after the test and before the set. Moving them closer together reduces the window for screw-ups but does not eliminate them. You almost always need a specially created mechanism from the language or kernel to fully close that window.

The threading library has Semaphores that can be used to synchronize threads and/or create critical sections of code.

Upvotes: 1

viraptor
viraptor

Reputation: 34205

Thread-safe in which way? I don't see any part you might want to protect here.

skip may reset the doSkip at any time, so there's not much point in locking it. You don't have any resources that are accessed at the same time - so IMHO nothing can be corrupted / unsafe in this code.

The only part that might run differently depending on locking / counting is how many "skip"s do you expect on every call to .skip(). If you want to ensure that every skip results in a skipped call to .work(), you should change doSkip into a counter that is protected by a lock on both increment and compare/decrement. Currently one thread might turn doSkip on after the check, but before the doSkip reset. It doesn't matter in this example, but in some real situation (with more code) it might make a difference.

Upvotes: 2

Martin
Martin

Reputation: 6032

This is and will thread safe as long as you don't share data between threads.

If an other thread needs to read/write data to your thread class, then this won't be thread safe unless you protect data with some synchronization mechanism (like locks).

Upvotes: 0

Bastien L&#233;onard
Bastien L&#233;onard

Reputation: 61833

Apparently there isn't any critical resource, so I'd say it's thread-safe.

But as usual you can't predict in which order the two threads will be blocked/run by the scheduler.

Upvotes: 0

Related Questions