2016-08-16 41 views
2

我來翻過這需要以下模式功能:如何在Python中使用鎖來保護對象?

from threading import Lock 

the_list = [] 
the_list_lock = Lock() 

,並使用它:

with the_list_lock: 
    the_list.append("New Element") 

不幸的是,這並不需要我去獲取鎖,我可以訪問直接對象。我希望對此有所保護(我只是人)。有沒有一個標準的方法來做到這一點?我自己的方法是創建一個HidingLock類可以這樣使用:

the_list = HidingLock([]) 
with the_list as l: 
    l.append("New Element") 

但感覺這樣基本的,要麼它應該在標準庫中存在,或者是使用鎖非常非常規的方式。

+0

含義需要一個鎖定的東西之前獲取的訪問?不是真的,你擁有的是預期的解決方案,爲它創建一個接口(即一個類)。而不是直接訪問列表,你可以通過類接口。 – danny

+0

你想保護訪問多遠?如果對象被傳遞給另一個線程,或者在with塊結束後繼續訪問,該怎麼辦? – Dunes

+0

@Dunes:防止意外忘記鎖定。我認爲在Python中不可能做到這一點。 'set'中的 –

回答

0

我目前的解決方案(一個我在這個問題談)看起來是這樣的:

import threading 

class HidingLock(object): 
    def __init__(self, obj, lock=None): 
     self.lock = lock or threading.RLock() 
     self._obj = obj 

    def __enter__(self): 
     self.lock.acquire() 
     return self._obj 

    def __exit__(self, exc_type, exc_value, traceback): 
     self.lock.release() 

    def set(self, obj): 
     with self: 
      self._obj = obj 

和這裏的人會如何使用它:

locked_list = HidingLock(["A"]) 
with locked_list as l: 
    l.append("B") 
+0

if條件有什麼用處。考慮到Thread1已經獲得了鎖而Thread2被稱爲set而沒有獲取,if條件仍然是true,並且Thread2將被允許改變_obj。 – Akilesh

+0

我編輯了使用可重入鎖定的代碼。各種線程現在可以調用set,並且只有一個獲得鎖的線程應該被允許改變_obj – Akilesh

+0

@Akilesh:我也想過了。然而,*如果每個'HidingLock.set'用法都被封裝在'with'塊中,則不需要使用'RLock',因爲調用'set()'時會獲得鎖。 –

0

怎麼樣創造一個shared_list具有list和使用threading.Lock實現所需的類方法:

import threading 

class SharedList(object): 
    def __init__(self, iterable=None): 
     if iterable is not None: 
      self.list = list(iterable) 
     else: 
      self.list = list() 
     self.lock = threading.Lock() 
     self.index = None 

    def append(self, x): 
     with self.lock: 
      self.list.append(x) 

    def __iter__(self): 
     shared_iterator = SharedList() 
     shared_iterator.list = self.list 
     shared_iterator.lock = self.lock 
     shared_iterator.index = 0 
     return shared_iterator 

    def next(self): 
     with self.lock: 
      if self.index < len(self.list): 
       result = self.list[self.index] 
       self.index += 1 
      else: 
       raise StopIteration 
      return result 

    # Override other methods 

if __name__ == '__main__': 
    shared_list = SharedList() 
    for x in range(1, 4): 
     shared_list.append(x) 
    for entry in shared_list: 
     print entry 

輸出

1 
2 
3 

由於Georg Shölly在評論中指出,這將需要很多工作來實現每種方法。但是,如果你需要的只是一個你可以附加到的列表,然後迭代,這個例子提供了一個起點。

然後,你可以只寫

the_list = SharedList() 
the_list.append("New Element") 
+0

重寫我想說的所有屬性是非常困難的。即使我們可以,像'__iter __()'這樣的方法也不是微不足道的,無法使線程安全。 –