title: Thread-safe Singleton doesn't work. Python
body: <p>I tried to find the bug, described in this <a href="https://stackoverflow.com/questions/32695984/python-multithreading-data-race">post</a>, and i found it.</p>
  
  <p>It's Singleton class, which i gave from StackOverflow from this <a href="https://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/7346105#7346105">post</a></p>
  
  <p>When i start testing that class, i found, that programm fall down (just like described in first link)...</p>
  
  <p>That's minimal example, that leads to bug:</p>
  
  <p><strong>Singleton.py</strong></p>
  
  <pre><code>import threading
  
  
  class Singleton(object):
      __singleton_lock = threading.Lock()
      __singleton_instance = None
  
      @classmethod
      def Instance(cls):
          if not cls.__singleton_instance:
              with cls.__singleton_lock:
                  if not cls.__singleton_instance:
                      cls.__singleton_instance = cls()
          return cls.__singleton_instance
  </code></pre>
  
  <p><strong>Data.py</strong></p>
  
  <pre><code>#-*- coding: utf-8 -*-
  from singletone import Singleton
  import threading
  
  
  class Data(Singleton):
  
      def __init__(self):
          self.task_table = {"Zadanie1.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie2.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie3.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie4.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie5.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie6.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie7.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie8.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie9.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie10.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie11.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie12.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie13.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie14.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie15.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie16.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie17.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie18.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie19.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie20.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie21.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie22.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie23.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie24.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie25.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie26.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie27.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie28.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie29.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie30.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie31.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie32.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie33.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie34.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie35.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie36.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie37.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie38.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie39.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie40.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie41.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie42.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie43.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie44.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie45.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie46.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie47.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie48.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie49.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie50.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie51.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie52.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie53.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie54.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie55.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie56.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie57.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie58.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie59.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie60.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie61.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie62.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie63.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie64.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie65.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie66.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie67.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie68.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie69.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie70.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie71.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie72.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie73.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie74.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie75.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie76.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie77.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie78.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie79.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie80.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie81.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie82.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie83.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie84.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie85.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie86.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie87.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie88.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie89.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie90.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie91.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie92.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie93.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie94.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie95.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie96.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie97.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie98.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie99.py": {'status': 'uncomplete', 'result': '', 'time': 0}, "Zadanie100.py": {'status': 'uncomplete', 'result': '', 'time': 0}}
          self.complete_task = threading.Event()
          self.complete_task.set()
  
      def getTotalCompleteTasks(self):
          result = 0
          for taskname in self.task_table.keys():
              if self.task_table[taskname]['status'] == 'complete':
                  result += 1
          return result
  </code></pre>
  
  <p><strong>Worker.py</strong></p>
  
  <pre><code>#-*- coding: utf-8 -*-
  import threading
  import subprocess
  
  
  class Worker(threading.Thread):
  
      def __init__(self, data, taskname):
          self.taskname = taskname
          self.data = data
          threading.Thread.__init__(self)
  
      def run(self):
          self.data.complete_task.clear()
          print u"Start executing %s" % self.taskname
          startupinfo = subprocess.STARTUPINFO()
          startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
          startupinfo.wShowWindow = subprocess.SW_HIDE
          p = subprocess.Popen("C:\Python27\python.exe tasks100.5\\" + self.taskname, startupinfo=startupinfo, shell=False, stdout=subprocess.PIPE)
          job_result, err = p.communicate()
          print u"Stop executing %s" % self.taskname
          self.data.task_table[self.taskname]['status'] = 'complete'
          self.data.complete_task.set()
  </code></pre>
  
  <p><strong>Agent.py</strong></p>
  
  <pre><code>#-*- coding: utf-8 -*-
  import communication_servers as cs
  from worker import Worker
  from data import Data
  import time
  
  
  app_data = Data.Instance()
  SRV = cs.Server(app_data)
  SRV.setDaemon(True)
  SRV.start()
  
  my_tasks = app_data.task_table.keys()[:]
  
  
  while True:
      print u"Complete tasks: %d\n" % app_data.getTotalCompleteTasks()
      time.sleep(1)
  
      if my_tasks:
          if app_data.complete_task.is_set():
              job = Worker(app_data, my_tasks.pop())
              job.setDaemon(True)
              print u"Running"
              job.start()
          else:
              print u"Can't run"
          print u"Test string"
  </code></pre>
  
  <p><strong>Communication_server.py</strong></p>
  
  <pre><code>#-*- coding: utf-8 -*-
  import threading
  import time
  
  
  class Server(threading.Thread):
  
      def __init__(self, data):
          threading.Thread.__init__(self)
  
      def run(self):
          while True:
              print('Server still working...\n')
              time.sleep(5)
  </code></pre>
  
  <p>All files like ZadanieXX.py is just there:</p>
  
  <pre><code>import time
  i = 2
  p = i**400
  time.sleep(5)
  print p
  </code></pre>
  
  <p>There is only reduce version of real code. And it's leads to bug just about in 1 case of 30 starts. The bug is when main while loop im Agent.py doesn't iterate or iterates, but <code>complete_task</code> event never sets (in less then 1 case of 100 starts).</p>
  
  <blockquote>
    <p>p.s.
    I tried to use <a href="http://rosettacode.org/wiki/Singleton#Python" rel="nofollow noreferrer">this</a> Singleton pattern, but bug is still here...</p>
  </blockquote>
  
  <p><strong><em>Any ideas, why it working in that way? Any proposal, how i can create single-instanced, thread-safety class to store all application working data?</em></strong></p>
  
  <blockquote class="spoiler">
    <p> My english is not very good. Sorry.</p>
  </blockquote>