我有一个对象,一次只能由一个线程使用。 例如,如果一个线程访问方法A
,我的对象包含3个方法A
,B
和C
,我想锁定对象(所有方法/属性都被锁定)。C#阻止从其他线程访问所有对象方法
主要难点是我无法修改该对象的代码。我必须防止多线程访问我调用对象。
我的第一个想法是使用单例模式,但我没有设法使它工作!
我有一个对象,一次只能由一个线程使用。 例如,如果一个线程访问方法A
,我的对象包含3个方法A
,B
和C
,我想锁定对象(所有方法/属性都被锁定)。C#阻止从其他线程访问所有对象方法
主要难点是我无法修改该对象的代码。我必须防止多线程访问我调用对象。
我的第一个想法是使用单例模式,但我没有设法使它工作!
如果无法更改对象的代码,则必须处理锁定以外的对象。例如,你可以将其封装在另一个类(也许隐藏在接口后面),并有包装类应用同步:
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(); } }
}
谢谢至少有2人注意到这不是另一个问题的完全重复! – darkheir 2012-08-14 09:32:52
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();
}
}
}
假设你不能只是建立每个线程一个对象,另一种方式是提高一个多线程调用非线程对象的方法,然后排队呼叫请求那一个线程。通常,线程应该在排队的请求中执行对非线程安全对象的请求操作后触发'OnCompletion'回调。
然后异步执行操作,但可以通过排队请求然后等待回调信号发出的事件来进行同步呼叫。
..只是另一种可能比在包装对象中简单锁定更灵活。
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方法获取锁定,则线程也可以获得一次性锁定。但是,应该注意的是,如果锁是通过这种方式获得的,它只会持续单个方法调用。
http://stackoverflow.com/questions/1344025/how-to-make-a-class-thread-safe – Freeman 2012-08-14 09:20:03
使用锁定(this){// ur functions} – Moons 2012-08-14 09:24:29
@Freeman:相关的,但不完全是因为海报不能修改他们课程的代码。 – 2012-08-14 09:25:12