0

I`m making the multithread system on python 2.7. Basically, it has 3 thread and one singleton-class with shared data.

Scheme of application Red arrow - invoke; Blue arrow - access

Every thread is separate class in a file. The file main.py import working and communication files, and shared data. Then main thread invoke working class in one thread and communication in another one thread. Herewith shared data, as only one instance of singleton, is passed in constructors of working class and communication class.

File main.py

import communication
import Worker
import Data

app_data = Data.Instance()
#...........

SRV = communication.Server(app_data)
SRV.setDaemon(True)
SRV.start()

#...........

while True
    #...........
    # MUST BE locker.acquire()
    if condition1:
        if condition2:
            job = Worker(app_data, SRV.taskResultSendToSlaves, app_data.ip_table[app_data.cfg.MY_IP]['tasks'].pop())
            job.setDaemon(True)
            job.start()
    # MUST BE locker.release()

File communication.py

class Server(threading.Thread):

    # .................

    def __init__(self, data):
        self.data = data
        # .................
        threading.Thread.__init__(self)

    def run(self):
        srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        srv.settimeout(self.data.cfg.TIMEOUT)
        srv.bind((self.my_addr, self.my_port))
        srv.listen(self.data.cfg.NUMBER_OF_CLIENTS)
        print "Start server"
        while True:
            # HANDLING MESSAGES FROM OTHER PC

    # .................

File Worker.py

class Worker(threading.Thread):    
    def __init__(self, data, sender, taskname):
        self.data = data
        self.sender = sender
        self.taskname = taskname
        threading.Thread.__init__(self)

    def run(self):
        import thread
        self.data.complete_task.clear()
        tick_before = time.time()
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        startupinfo.wShowWindow = subprocess.SW_HIDE
        p = subprocess.Popen(self.data.cfg.PATH_INTERPRETER + " " + self.data.cfg.PATH_TASKS + self.taskname, startupinfo=startupinfo, shell=False, stdout=subprocess.PIPE)
        job_result, err = p.communicate()
        tick_after = time.time()
        work_time = tick_after - tick_before  
        # MUST BE locker.acquire()      
        self.data.task_table[self.taskname]['status'] = 'complete'
        self.data.task_table[self.taskname]['result'] = job_result
        self.data.task_table[self.taskname]['time'] = work_time
        # MUST BE locker.release()
        logging.debug("%s task is done" % self.taskname)
        tr = threading.Thread(target=self.sender, name="SENDER", args=(self.taskname, ))
        tr.setDaemon(True)
        tr.start()
        tr.join()
        logging.debug("%s task is sent" % self.taskname)
        self.data.complete_task.set()
        thread.exit()

Singletone.py

class Singleton:

    def __init__(self, decorated):
        self._decorated = decorated

    def Instance(self):
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

def __call__(self):
    raise TypeError('Singletons must be accessed through `Instance()`.')

def __instancecheck__(self, inst):
    return isinstance(inst, self._decorated)

data.py

#-*- coding: utf-8 -*-
from singletone import Singleton
from configs import Configurations
import threading
import logging


@Singleton
class Data:

    def __init__(self):
        logging.basicConfig(format=u'%(filename)-10s[LINE:%(lineno)d] <%(funcName)-15s> # %(levelname)-8s [%(asctime)s]  %(message)s'.encode('cp1251', 'ignore'), level=logging.DEBUG, filename='mylog.log')
        logging.log(100, '='*120)
        self.cfg = Configurations()
        self.ip_table = self.getIPTable()
        self.task_table = self.getTaskTable()
        self.locker = threading.Lock()
        self.initialization = threading.Event()
        self.initialization.clear()
        self.identification = threading.Event()
        self.identification.clear()
        self.complete_task = threading.Event()
        self.complete_task.set()
        self.flag_of_close = False

    def __str__(self):
        return "\
        {0}\n\
        \n\
        {1}\n\
        \n\
        {2}\n\
        ".format(str(self.cfg), self.strIPTable(), self.strTaskTable())

    def strIPTable(self):
        #return str(self.ip_table)
        result = ["%s = %s" % (key, str(value)) for key, value in self.ip_table.items()]
        result.sort()
        return "\n\t\t".join(result)

    def strTaskTable(self):
        #return str(self.task_table)
        result = ["%s = %s" % (key, str(value)) for key, value in self.task_table.items()]
        result.sort()
        return "\n\t\t".join(result)

    def getIPTable(self):
        result = {}
        if self.cfg.IPS:
            result = dict((item.strip(), {'status': True, 'port': 8000, 'tasks': []}) for item in self.cfg.IPS.split(','))
            # result = dict((item.strip(), {'status': False, 'port': 8000, 'tasks': []}) for item in self.cfg.IPS.split(','))
        result[self.cfg.MY_IP] = {'status': True, 'port': 8000, 'tasks': []}
        return result

    def getTaskTable(self):
        result = {}
        if self.cfg.TASKS:
            result = dict((item.strip(), {'status': 'uncomplete', 'result': '', 'time': 0}) for item in self.cfg.TASKS.split(','))
        return result

    def getTotalCompleteTasks(self):
        result = 0
        for taskname in self.task_table.keys():
            if self.task_table[taskname]['status'] == 'complete':
                result += 1
        return result


if __name__ == '__main__':
    data = Data.Instance()
    print data

Singleton i has stolen from stackoverflow

After start this system, sometimes a have a data race. When working and main thread at the same time read shared data. I think we need a threading.Lock here. Then i did a mistake, i put Lock object in shared data and have used it to separate access. Shortly a have understand my mistake.

Filenames has changed, some pieces of code has removed.

But for now i don't know where i must put Lock object, that every thread can easily and in a right way access and use it. Can you give me advice?

My english is not very good, so be tolerant. I hope you understand my question...

App is running

P.S.

Besides that, i tried to pass Lock() object in constructors of classes. And i have same trouble. The application has fallen somewhere, where data was accessed. And i can't find out where exactly it is. Every start can fall down application with 50% probability.

Worker file Main file

murzagurskiy
  • 1,055
  • 1
  • 16
  • 37
  • Can you please post the code of the data singleton? You typically want to use locks inside the shared data structure. I see you've added locks to the main loop, which seems completely irrelevant to what you're trying to accomplish. – Alex Sep 21 '15 at 13:11
  • @Alex i had added pictures and code. – murzagurskiy Sep 21 '15 at 13:44

1 Answers1

0

I found the bug. It was Singleton class, but i don't know how to fix it.

murzagurskiy
  • 1,055
  • 1
  • 16
  • 37