jny*_*len 1 c# multithreading threadpool
我不太清楚怎么说这个,所以我只是粘贴我的代码并提出问题:
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);
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
假设修改status对象的任何其他代码将首先获得对它的锁定.
由于status对象一直传递到多个ThreadPool线程,并且调用ThreadPool.QueueUserWorkItem将在实际任务完成之前完成,我是否确保将相同的status对象发送到所有客户端?
换句话说,lock (status)语句何时"过期"或导致其锁被释放?
锁不会过期.当一个线程试图传递该lock语句时,它只能在没有其他线程在一个lock块内执行的情况下执行它,该块在lockstatemement中使用的特定对象实例上有锁定.
在你的情况下,似乎你有一个主线程正在执行.它会在旋转在单独线程上执行的新任务之前锁定实例status和clients实例.如果新线程中的任何代码想要获取锁定,status或者clients它必须等到主线程通过保留两个lock块来释放两个锁.remoteAction_JobStatusUpdated返回时会发生这种情况
您将status对象传递给每个工作线程,并且他们可以自由地对该对象执行任何操作.该声明lock (status)绝不保护status实例.但是,如果任何线程尝试执行,lock (status)它们将阻塞,直到主线程释放锁.
使用两个单独的对象实例进行锁定可能会导致死锁.假设一个线程执行以下代码:
lock (status) {
...
lock (clients) {
...
}
Run Code Online (Sandbox Code Playgroud)
}
另一个线程执行以下代码,其中以相反的顺序获取锁:
lock (clients) {
...
lock (status) {
...
}
Run Code Online (Sandbox Code Playgroud)
}
如果第一个线程设法首先获得状态,而第二个线程首先锁定客户端,则它们将处于死锁状态,并且两个线程将不再运行.
一般情况下,我建议您将共享状态封装在一个单独的类中,并使其可以访问它的线程安全:
class State {
readonly Object locker = new Object();
public void ModifyState() {
lock (this.locker) {
...
}
}
public String AccessState() {
lock (this.locker) {
...
return ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
您也可以使用[MethodImpl(MethodImpl.Synchronized)]属性标记方法,但它有其缺陷,因为它将围绕方法,lock (this)通常不推荐使用.
如果您想更好地了解lock语句幕后的内容,可以阅读MSDN Magazine中的" 安全线程同步"一文.