Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a synchronized function across all instances

I want to create a synchronized method in python with respect to some CRUD functions on all instances of a class. For example while create is called and ongoing by a thread, delete needs to wait on the same object.

Can someone please tell me if the code below is correct. I may have some syntax error but what I want to know is if the lock is going to be the same across calls to create ALL instances of this class and therefore if any instance create/delete is in progress delete/create on the same or other instances by another thread will have to wait?

import threading
import functools

def synchronized(wrapped):
    lock = threading.Lock()
    @functools.wraps(wrapped)
    def _wrap(*args, **kwargs):
        with lock:
            return wrapped(*args, **kwargs)
    return _wrap

class AtomicCRUD(object):

    @synchronized
    def create(self):
        #Do stuff that may take a while here. 
        pass

    @synchronized
    def delete(self):
       #Do stuff that may take a while here. 
       pass 

My understanding of python is synchronized will be called for each of create/delete function object. I put a print statement in the synchronized function above for the lock object and did a test run using the following:

@synchronized
def test1():
    print "test1"


@synchronized
def test2():
    print "test2"

And I get the following output, which makes me think the lock used is the same for both function objects. I don't seem to understand how this works.

<Semaphore c=1 _w[0]>
<Semaphore c=1 _w[0]>
test1
test2
like image 503
as3rdaccount Avatar asked Mar 20 '15 02:03

as3rdaccount


People also ask

What are two methods of synchronization?

The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements.

How many threads per instance can execute inside a synchronized?

Only one thread per instance can execute inside a synchronized instance method.

What is a synchronized in multi threading?

Synchronization in java is the capability to control the access of multiple threads to any shared resource. In the Multithreading concept, multiple threads try to access the shared resources at a time to produce inconsistent results. The synchronization is necessary for reliable communication between threads.


1 Answers

Your output prints the same <Semaphore c=1 _w[0]> but it doesn't necessarily indicate that those are the same objects. It depends what your print statement is.

To make sure you are not using the same Lock object you could add a print statement in the _wrap function as follow:

def synchronized(wrapped):
    lock = threading.Lock()
    @functools.wraps(wrapped)
    def _wrap(*args, **kwargs):
        print "Calling '%s' with Lock %s" % (wrapped.__name__, id(lock))
        with lock:
            return wrapped(*args, **kwargs)
    return _wrap

You will get a different id printed every time you call create or delete:

AtomicCRUD().delete()
# Calling 'delete' with Lock 3075170560
AtomicCRUD().delete() 
# Calling 'delete' with Lock 3075170560
AtomicCRUD().create() 
# Calling 'create' with Lock 3075170544                                    
AtomicCRUD().create() 
# Calling 'create' with Lock 3075170544

The decorator synchronized is only call twice - when the interpreter reads the decorated method declaration. The decorator "replace" the decorated method with the implementation of _wrap but not with what is above functools.wraps(wrapped) so the Lock is only created once per decorated method.

Each decorated method has its own Lock.

In the code above we can also see that this works for any instance of AtomicCRUD since we re-instantiate an object every time but the result is the same when using a single instance

crud = AtomicCRUD()                                                             
crud.delete()
# Calling 'delete' with Lock 3075059968                                                             
crud.delete()
# Calling 'delete' with Lock 3075059968
crud.create()
# Calling 'create' with Lock 3075059952
crud.create()
# Calling 'create' with Lock 3075059952

And with a complete example we can see that the Locks behave as expected:

import threading                                                                
import functools                                                                
import time                                                                     


def synchronized(wrapped):                                                      
    lock = threading.Lock()                                                     
    print lock, id(lock)                                                        
    @functools.wraps(wrapped)                                                   
    def _wrap(*args, **kwargs):                                                 
        with lock:                                                              
            print ("Calling '%s' with Lock %s from thread %s [%s]"              
                   % (wrapped.__name__, id(lock),                               
                   threading.current_thread().name, time.time()))               
            result = wrapped(*args, **kwargs)                                   
            print ("Done '%s' with Lock %s from thread %s [%s]"                 
                   % (wrapped.__name__, id(lock),                               
                   threading.current_thread().name, time.time()))               
            return result                                                       
    return _wrap                                                                

class AtomicCRUD(object):                                                       

    @synchronized                                                               
    def create(self):                                                           
        #Do stuff that may take a while here.                                   
        time.sleep(1)                                                           

    @synchronized                                                               
    def delete(self):                                                           
        #Do stuff that may take a while here.                                   
        time.sleep(1)                                                           


class SyncThread(threading.Thread):                                             

    def __init__(self, crud, name):                                             
        super(self.__class__, self).__init__(name=name)                         
        self._crud = crud                                                       

    def run(self):                                                              
        self._crud.create()                                                     
        self._crud.delete()                                                     


crud = AtomicCRUD()                                                             
threads = [SyncThread(crud, "Thread_%d" % i) for i in range(5)]                 
for t in threads:                                                               
    t.start()                                                                   

for t in threads:                                                               
    t.join()   

The output shows that create cannot be called at the same time from different threads. But delete and create can be called at the same time from different thread.

like image 52
El Bert Avatar answered Sep 30 '22 08:09

El Bert