gpt4 book ai didi

C# ConcurrentDictionary 与线程控制的 ManualResetEvent

转载 作者:太空宇宙 更新时间:2023-11-03 15:49:11 27 4
gpt4 key购买 nike

我有一个 Windows 服务,它使用带有回调的 System.Threading.Timer 来更新端点,如下所示:

UpdateEndpointTimer = new Timer(
new TimerCallback(UpdateSBEndpoints),
Endpoint.Statuses.Online,
EndpointUpdateFrequency,
EndpointUpdateFrequency);

我的更新方法大致如下:

private void UpdateSBEndpoints(object state)
{
...
using (var context = new TestHarnessContext())
{
var endpoints = context.Endpoints.Where(p =>
p.Binding == Endpoint.Bindings.ServiceBus
&& p.State == Endpoint.States.Enabled
&& p.Status != status).ToList();

foreach (var endpoint in endpoints)
{
//Do stuff here
}
...
}

现在,由于计时器使用 ThreadPool 中的线程来触发回调,我需要采取措施来控制线程。当多个线程可以在第一个线程完成工作之前从数据库中获取相同的端点时,就会出现一个特定的问题,这会导致在 foreach 循环中完成重复的工作。

我知道该问题有两种可能的解决方案,我想知道哪一种更好,更适合使用。解决方案是 ConcurrentDictionaryManualResetEvent

在第一种情况下,我会把它放在我的 foreach 循环中,以确保一次只有一个线程可以在给定的端点上运行:

if (EndpointsInAction.TryAdd(endpoint.Id, endpoint.Id) == false)
// If we get here, another thread has started work with this endpoint.
return;
...
//Do stuff with the endpoint, once done, remove its Id from the dictionary
...
int id;
EndpointsInAction.TryRemove(endpoint.Id, out id);

在第二种情况下,我会像这样控制线程:

protected ManualResetEvent PubIsBeingCreated { get; set; }
protected ManualResetEvent SubIsBeingCreated { get; set; }
...
this.PubIsBeingCreated = new ManualResetEvent(true);
this.SubIsBeingCreated = new ManualResetEvent(true);
...
foreach (var endpoint in endpoints)
{
if (!this.PubIsBeingCreated.WaitOne(0))
// If we get here, another thread has started work with this endpoint.
return;

try
{
// block other threads (Timer Events)
PubIsBeingCreated.Reset();
// Do stuff
}
...
finally
{
// Restore access for other threads
PubIsBeingCreated.Set();
}
}

现在这两种方法似乎都有效我想知道哪种方法更适合使用(效率更高?)。我倾向于使用 ConcurrentDictionary,因为它允许更好地过滤线程,即不允许两个线程与特定端点一起工作,而不允许两个线程与特定端点一起工作类型(ManualResetEvents 中的发布和订阅)。可能有其他解决方案优于我的解决方案,因此我们将不胜感激。

最佳答案

在任何情况下,您都不应为此目的使用 ManualResetEvent。使用提供更高级别抽象的对象总是更好,但即使您想在低级别控制它,也可以使用 .NET 的 Monitor 类(通过 lock 语句和 Monitor .Wait()Monitor.Pulse() 方法比使用 ManualResetEvent 更好。

您似乎有一个相当标准的生产者/消费者场景。在那种情况下,在我看来,您最好使用 ConcurrentQueue 而不是 ConcurrentDictionary。您的生产者会将事物排入队列,而您的消费线程会将它们从队列中取出以进行处理。

关于C# ConcurrentDictionary 与线程控制的 ManualResetEvent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26639150/

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