传递给其他线程的对象上的锁会发生什么情况?
我不太确定如何表达这一点,所以我只是粘贴我的代码并提出问题:
private void remoteAction_JobStatusUpdated(JobStatus status) {
lock (status) {
status.LastUpdatedTime = DateTime.Now;
doForEachClient(c => c.OnJobStatusUpdated(status));
OnJobStatusUpdated(status);
}
}
private void doForEachClient(Action<IRemoteClient> task) {
lock (clients) {
foreach (KeyValuePair<RemoteClientId, IRemoteClient> entry in clients) {
IRemoteClient clientProxy = entry.Value;
RemoteClientId clientId = entry.Key;
ThreadPool.QueueUserWorkItem(delegate {
try {
task(clientProxy);
#pragma warning disable 168
} catch (CommunicationException ex) {
#pragma warning restore 168
RemoveClient(clientId);
}
});
}
}
}
假设修改 status
对象的任何其他代码将首先获取它的锁。
由于 status
对象会一直传递到多个 ThreadPool
线程,并且对 ThreadPool.QueueUserWorkItem
的调用将在实际任务完成之前完成,我是否确保将相同的 status
对象发送给所有客户端?
换句话说,lock (status)
语句何时“过期”或导致其锁被释放?
I'm not quite sure how to word this, so I'll just paste my code and ask the question:
private void remoteAction_JobStatusUpdated(JobStatus status) {
lock (status) {
status.LastUpdatedTime = DateTime.Now;
doForEachClient(c => c.OnJobStatusUpdated(status));
OnJobStatusUpdated(status);
}
}
private void doForEachClient(Action<IRemoteClient> task) {
lock (clients) {
foreach (KeyValuePair<RemoteClientId, IRemoteClient> entry in clients) {
IRemoteClient clientProxy = entry.Value;
RemoteClientId clientId = entry.Key;
ThreadPool.QueueUserWorkItem(delegate {
try {
task(clientProxy);
#pragma warning disable 168
} catch (CommunicationException ex) {
#pragma warning restore 168
RemoveClient(clientId);
}
});
}
}
}
Assume that any other code which modifies the status
object will acquire a lock on it first.
Since the status
object is passed all the way through to multiple ThreadPool
threads, and the call to ThreadPool.QueueUserWorkItem
will complete before the actual tasks complete, am I ensuring that the same status
object gets sent to all clients?
Put another way, when does the lock (status)
statement "expire" or cause its lock to be released?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
锁不会过期。当一个线程尝试传递
lock
语句时,只有在lock
块内没有其他线程正在执行该语句时,该块才能执行此操作,该块对lock
中使用的特定对象实例具有锁定。代码>锁定语句。在你的情况下,你似乎有一个正在执行的主线程。在旋转在单独线程上执行的新任务之前,它将锁定
status
和clients
实例。如果新线程中的任何代码想要获取status
或clients
上的锁,则必须等待,直到主线程通过保留两个来释放这两个锁。锁定
块。当remoteAction_JobStatusUpdated
返回时就会发生这种情况。您将
status
对象传递给每个工作线程,它们都可以自由地对该对象执行任何操作。lock (status)
语句绝不会保护status
实例。但是,如果任何线程尝试执行lock (status)
,它们将阻塞,直到主线程释放锁。使用两个单独的对象实例来锁定可能会导致死锁。假设一个线程执行以下代码:
}
另一个线程执行以下代码,其中以相反的顺序获取锁:
}
如果第一个线程首先获得状态,而第二个线程首先获得客户端锁定,则它们会死锁,并且两个线程都会不再运行。
一般来说,我建议您将共享状态封装在一个单独的类中,并使其访问线程安全:
您还可以使用 [MethodImpl(MethodImpl.Synchronized)] 属性,但它有其缺陷,因为它会用
锁包围该方法(this)
通常不推荐这样做。如果您想更好地了解
lock
语句的幕后情况,您可以阅读 MSDN 杂志中的安全线程同步文章。Locks don't expire. When a thread tries to pass the
lock
statement it can only do it if no other thread is executing inside alock
block having a lock on that particular object instance used in thelock
statemement.In your case it seems that you have a main thread executing. It will lock both the
status
and theclients
instances before it spins of new tasks that are executed on seperate threads. If any code in the new threads want to acquire a lock on eitherstatus
orclients
it will have to wait until the main thread has released both locks by leaving bothlock
blocks. That happens whenremoteAction_JobStatusUpdated
returns.You pass the
status
object to each worker thread and they are all free to do whatever they want to do with that object. The statementlock (status)
in no way protects thestatus
instance. However, if any of the threads tries to executelock (status)
they will block until the main thread releases the lock.Using two separate object instances to lock can lead to deadlock. Assume one thread executes the following code:
}
Another thread executes the following code where the locks are acquired in the reverse sequence:
}
If the first thread manages to get the status first and the second the clients lock first they are deadlocked and both threads will no longer run.
In general I would advice you to encapsulate your shared state in a separate class and make access to it thread safe:
You can also mark you methods with the [MethodImpl(MethodImpl.Synchronized)] attribute, but it has its pitfalls as it will surround the method with a
lock (this)
which in general isn't recommended.If you want to better understand what is going on behind the scenes of the
lock
statement you can read the Safe Thread Synchronization article in MSDN Magazine.锁当然不会自行“过期”,锁在 lock(..){} 语句的右大括号之前一直有效。
The locks certainly don't "expire" on their own, the lock will be valid until the closing brace of the lock(..){} statement.