2012-08-14 54 views
3

我有一个对象,一次只能由一个线程使用。 例如,如果一个线程访问方法A,我的对象包含3个方法ABC,我想锁定对象(所有方法/属性都被锁定)。C#阻止从其他线程访问所有对象方法

主要难点是我无法修改该对象的代码。我必须防止多线程访问我调用对象。

我的第一个想法是使用单例模式,但我没有设法使它工作!

+4

http://stackoverflow.com/questions/1344025/how-to-make-a-class-thread-safe – Freeman 2012-08-14 09:20:03

+0

使用锁定(this){// ur functions} – Moons 2012-08-14 09:24:29

+2

@Freeman:相关的,但不完全是因为海报不能修改他们课程的代码。 – 2012-08-14 09:25:12

回答

9

如果无法更改对象的代码,则必须处理锁定以外的对象。例如,你可以将其封装在另一个类(也许隐藏在接口后面),并有包装类应用同步:

public class Foo { 
    private readonly YourType tail; 
    private readonly object syncLock = new object(); 
    public Foo(YourType tail) {this.tail = tail;} 

    public A() { lock(syncLock) { tail.A(); } } 
    public B() { lock(syncLock) { tail.B(); } } 
    public C() { lock(syncLock) { tail.C(); } } 
} 
+0

谢谢至少有2人注意到这不是另一个问题的完全重复! – darkheir 2012-08-14 09:32:52

5

Singleton模式是不是在这里是正确的 - 它可以确保只有有一个对象的单个实例,但并不指定如何使用它。

代码中的线程安全性必须在代码中定义。也就是说,如果你不能修改你的对象的代码,你将无法正确地线程安全。但是,有一种解决方法:您可以将对象包装在您创建的新类中,并确保您的新对象线程安全。通过为你的不安全对象的方法公开线程安全的包装器,你可以确保它以你想要的方式访问。

最简单的方法是使用lock关键字。像这样的东西可能会奏效:

public class ThreadSafeThing 
{ 
    private UnsafeThing _thing = new UnsafeThing(); 
    private object _syncRoot = new object(); 

    public void DoSomething() // this is your thread-safe version of Thing.DoSomething 
    { 
     lock (_syncRoot) 
     { 
      _thing.DoSomething(); 
     } 
    } 
} 
0

假设你不能只是建立每个线程一个对象,另一种方式是提高一个多线程调用非线程对象的方法,然后排队呼叫请求那一个线程。通常,线程应该在排队的请求中执行对非线程安全对象的请求操作后触发'OnCompletion'回调。

然后异步执行操作,但可以通过排队请求然后等待回调信号发出的事件来进行同步呼叫。

..只是另一种可能比在包装对象中简单锁定更灵活。

1

OP没有指定,但是如果他的scenerio包含他需要保持跨多个客户端调用锁定对象的可能性(例如他需要从客户端调用函数A,那么根据结果调用函数B或C,保持对象锁定到其他线程的整个时间),你需要不同的方式实现了一下,例如:

public static class ThreadSafeThing { 
    private static UnsafeThing _thing = new UnsafeThing(); 
    private static readonly object _lock = new object(); 

    public static void getLock() { 
     Monitor.Enter(_lock); 
    } 

    public static void releaseLock() { 
     Monitor.Exit(_lock); 
    } 

    // this is your thread-safe version of Thing.DoSomething    
    public static bool DoSomething() { 
     try { 
      Monitor.Enter(_lock); 
      return _thing.DoSomething(); 
     } 
     finally { 
      Monitor.Exit(_lock); 
     } 
    } 

    // this is your thread-safe version of Thing.DoSomethingElse 
    public static void DoSomethingElse() { 
     try { 
      Monitor.Enter(_lock); 
      return _thing.DoSomethingElse(); 
     } 
     finally { 
      Monitor.Exit(_lock); 
     } 
    } 
} 

从像这样的客户电话...

try { 
    ThreadSafeThing.getLock(); 
    if (ThreadSafeThing.DoSomething()) { 
     ThreadSafeThing.DoSomethingElse(); 
    } 
} 
finally { 
    // This must be called no matter what happens 
    ThreadSafeThing.releaseLock(); 
} 

的这里的主要区别是客户负责一旦完成,获得一个锁并释放它。这允许在维持锁的同时调用对象上的多个函数。所有其他线程将在getLock调用上阻塞,直到锁使用releaseLock释放。

编辑:在DoSomething和DoSomethingElse方法中添加了自动获取锁定,如果直接调用这些方法而不通过getLock方法获取锁定,则线程也可以获得一次性锁定。但是,应该注意的是,如果锁是通过这种方式获得的,它只会持续单个方法调用。

相关问题