C# 传递给其他线程的对象上的锁会发生什么情况?
我不太清楚该如何表达,所以我将粘贴我的代码并提出以下问题:C# 传递给其他线程的对象上的锁会发生什么情况?,c#,multithreading,threadpool,C#,Multithreading,Threadpool,我不太清楚该如何表达,所以我将粘贴我的代码并提出以下问题: private void remoteAction_JobStatusUpdated(JobStatus status) { lock (status) { status.LastUpdatedTime = DateTime.Now; doForEachClient(c => c.OnJobStatusUpdated(status)); OnJobStatusUpdated(
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);
}
});
}
}
}
private void remoteAction\u作业状态更新(作业状态){
锁定(状态){
status.lastUpdateTime=DateTime.Now;
doForEachClient(c=>c.OnJobStatusUpdated(状态));
OnJobStatusUpdated(状态);
}
}
私有void doForEachClient(操作任务){
锁定(客户端){
foreach(客户端中的KeyValuePair条目){
IRemoteClient clientProxy=entry.Value;
RemoteClientId clientId=entry.Key;
ThreadPool.QueueUserWorkItem(委托{
试一试{
任务(clientProxy);
#pragma警告禁用168
}捕获(通信例外){
#pragma警告恢复168
RemoveClient(客户端ID);
}
});
}
}
}
假设修改状态
对象的任何其他代码都将首先获得该对象的锁
由于status
对象一直传递到多个ThreadPool
线程,并且对ThreadPool.QueueUserWorkItem
的调用将在实际任务完成之前完成,我是否确保将相同的status
对象发送到所有客户端
换句话说,lock(status)
语句何时“过期”或导致其锁被释放?锁不会过期。当一个线程试图传递lock
语句时,它只能在lock
块内没有其他线程在lock
语句中使用的特定对象实例上有锁的情况下执行
在您的例子中,似乎有一个主线程正在执行。它将锁定状态
和客户端
实例,然后再旋转在不同线程上执行的新任务。如果新线程中的任何代码希望在状态
或客户端
上获取锁,则必须等待主线程通过保留两个锁
块来释放两个锁。当remoteAction\u JobStatusUpdated
返回时会发生这种情况
您将状态
对象传递给每个工作线程,它们都可以自由地对该对象执行任何操作。语句lock(status)
绝不保护status
实例。但是,如果任何线程尝试执行lock(status)
,它们将阻塞,直到主线程释放锁为止
使用两个单独的对象实例进行锁定可能会导致死锁。假设一个线程执行以下代码:
lock (status) {
...
lock (clients) {
...
}
}
另一个线程在以相反顺序获取锁的位置执行以下代码:
lock (clients) {
...
lock (status) {
...
}
}
如果第一个线程设法获得第一个和第二个状态,那么客户端首先锁定它们,它们将处于死锁状态,两个线程将不再运行
一般来说,我建议您将共享状态封装在单独的类中,并使对它的访问线程安全:
class State {
readonly Object locker = new Object();
public void ModifyState() {
lock (this.locker) {
...
}
}
public String AccessState() {
lock (this.locker) {
...
return ...
}
}
}
您也可以使用属性标记方法,但它有它的缺陷,因为它会在方法周围使用锁(this)
,通常不推荐使用该锁
如果您想更好地了解lock
语句背后的情况,可以阅读MSDN杂志上的文章。锁不会过期。当一个线程试图传递lock
语句时,它只能在lock
块内没有其他线程在lock
语句中使用的特定对象实例上有锁的情况下执行
在您的例子中,似乎有一个主线程正在执行。它将锁定状态
和客户端
实例,然后再旋转在不同线程上执行的新任务。如果新线程中的任何代码希望在状态
或客户端
上获取锁,则必须等待主线程通过保留两个锁
块来释放两个锁。当remoteAction\u JobStatusUpdated
返回时会发生这种情况
您将状态
对象传递给每个工作线程,它们都可以自由地对该对象执行任何操作。语句lock(status)
绝不保护status
实例。但是,如果任何线程尝试执行lock(status)
,它们将阻塞,直到主线程释放锁为止
使用两个单独的对象实例进行锁定可能会导致死锁。假设一个线程执行以下代码:
lock (status) {
...
lock (clients) {
...
}
}
另一个线程在以相反顺序获取锁的位置执行以下代码:
lock (clients) {
...
lock (status) {
...
}
}
如果第一个线程设法获得第一个和第二个状态,那么客户端首先锁定它们,它们将处于死锁状态,两个线程将不再运行
一般来说,我建议您将共享状态封装在单独的类中,并使对它的访问线程安全:
class State {
readonly Object locker = new Object();
public void ModifyState() {
lock (this.locker) {
...
}
}
public String AccessState() {
lock (this.locker) {
...
return ...
}
}
}
您也可以使用属性标记方法,但它有它的缺陷,因为它会在方法周围使用锁(this)
,通常不推荐使用该锁
如果您想更好地了解
lock
语句的幕后情况,可以阅读MSDN杂志上的文章。锁肯定不会自行“过期”,锁将在lock(…){}语句的右括号之前有效 锁当然不会自行“过期”,锁将一直有效,直到lock(..{}语句的右括号结束 “Expire”是一个糟糕的用词选择。“Expire”是一个糟糕的用词选择。编辑了这个问题,希望能澄清我的措辞。我忘了说任何其他修改我的状态的代码都会首先在对象上获得一个锁。不管怎样,这回答了我的问题,谢谢。一个问题,