gpt4 book ai didi

c# - 第二个线程是否可以仅仅因为第一个线程使用相同的同步锁调用 Monitor.Wait 而进入相同的临界区?

转载 作者:行者123 更新时间:2023-11-30 15:21:32 24 4
gpt4 key购买 nike

请告诉我,如果我觉得还好。

  1. 不同的线程不能进入相同的临界区使用同样的锁只是因为第一个线程调用了Monitor.Wait,对吧? Wait 方法只允许不同的线程获取相同的监视器,即相同的同步锁,但仅用于不同的关键部分,而不是相同的关键部分节

    我的理解正确吗?

    因为如果 Wait 方法意味着任何人现在都可以输入 this相同的关键部分使用相同的锁,那么这将失败同步的全部目的,对吗?

    所以,在下面的代码中(用记事本写的,所以请原谅任何错别字),ThreadProc2只能使用syncLock进入代码ThreadProc2 而不是 ThreadProc1 而前一个线程持有并随后放弃锁的人正在执行ThreadProc1,对吧?

  2. 两个或多个线程可以使用同一个同步锁来运行同时处理不同的代码,对吗?同样的问题以上,基本上,但只是为了对称而确认下面第 3 点。

  3. 两个或多个线程可以使用不同的同步锁来运行同一段代码,即进入同一临界区。

用于更正格式的样板文本。

class Foo
{
private static object syncLock = new object();

public void ThreadProc1()
{
try
{
Monitor.Enter(syncLock);

Monitor.Wait(syncLock);

Thread.Sleep(1000);
}
finally
{
if (Monitor.IsLocked(syncLock))
{
Monitor.Exit(syncLock);
}
}
}

public void ThreadProc2()
{
bool acquired = false;

try
{
// Calling TryEnter instead of
// Enter just for the sake of variety
Monitor.TryEnter(syncLock, ref acquired);

if (acquired)
{
Thread.Sleep(200);
Monitor.Pulse(syncLock);
}
}
finally
{
if (acquired)
{
Monitor.Exit(syncLock);
}
}
}
}

更新

下图证实了#3 是正确的,尽管我认为这不是一件好事。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DifferentSyncLockSameCriticalSection
{
class Program
{
static void Main(string[] args)
{
var sathyaish = new Person { Name = "Sathyaish Chakravarthy" };
var superman = new Person { Name = "Superman" };
var tasks = new List<Task>();

// Must not lock on string so I am using
// an object of the Person class as a lock
tasks.Add(Task.Run( () => { Proc1(sathyaish); } ));
tasks.Add(Task.Run(() => { Proc1(superman); }));

Task.WhenAll(tasks);

Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}

static void Proc1(object state)
{
// Although this would be a very bad practice
lock(state)
{
try
{
Console.WriteLine((state.ToString()).Length);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}

class Person
{
public string Name { get; set; }

public override string ToString()
{
return Name;
}
}
}

最佳答案

当线程调用 Monitor.Wait 时,它会被挂起并释放锁。这将允许另一个线程获取锁、更新一些状态,然后调用 Monitor.Pulse 以便与其他线程通信发生了某些事情。您必须获得锁才能调用 Pulse。在 Monitor.Wait 返回之前,框架将重新获取调用 Wait 的线程的锁。

为了让两个线程相互通信,它们需要使用相同的同步原语。在您的示例中,您使用了监视器,但您通常需要将其与 Wait 响应 Pulse 返回的某种测试相结合。这是因为即使未调用 Pulse,技术上也可以Wait 返回(尽管这在实践中不会发生)。

还值得记住的是,对 Pulse 的调用不是“粘性”的,因此如果没有人在等待监视器,则 Pulse 什么都不做,随后调用Wait 将错过 Pulse 被调用的事实。这是您倾向于在调用 Pulse 之前记录已完成某事的另一个原因(请参见下面的示例)。

两个不同的线程使用同一个锁来运行不同的代码位是完全有效的——事实上这是典型的用例。例如,一个线程获取锁以写入一些数据,而另一个线程获取锁以读取数据。但是,重要的是要认识到它们不会同时运行。获取锁的行为会阻止另一个线程获取相同的锁,因此任何试图在它已经被锁定时获取锁的线程都将阻塞,直到另一个线程释放锁。

在第 3 点你问:

Two or more threads can use a different synchronization lock to run the same piece of code, i.e. to enter the same critical section.

但是,如果两个线程使用不同的锁,则它们不会进入同一临界区。关键部分由保护它的锁表示——如果它们是不同的锁,那么它们是不同的部分,只是碰巧访问该部分中的一些公共(public)数据。您应该避免这样做,因为它会导致一些难以调试的数据竞争条件。

您的代码对于您要实现的目标来说有点过于复杂。例如,假设我们有 2 个线程,当有数据可供另一个线程处理时,一个会发出信号:

    class Foo
{
private readonly object syncLock = new object();
private bool dataAvailable = false;

public void ThreadProc1()
{
lock(syncLock)
{
while(!dataAvailable)
{
// Release the lock and suspend
Monitor.Wait(syncLock);
}

// Now process the data
}
}

public void ThreadProc2()
{
LoadData();

lock(syncLock)
{
dataAvailable = true;
Monitor.Pulse(syncLock);
}
}

private void LoadData()
{
// Gets some data
}
}
}

关于c# - 第二个线程是否可以仅仅因为第一个线程使用相同的同步锁调用 Monitor.Wait 而进入相同的临界区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37394688/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com