c# - 在 .NET 中使用 Interlocked 类进行多线程处理的正确方法

标签 c# .net multithreading locking

我有一个计数器,统计当前处理的大报表

private int processedLargeReports;

我正在生成并启动五个线程,其中每个线程都访问此方法:

public bool GenerateReport(EstimatedReportSize reportSize)
{
    var currentDateTime = DateTimeFactory.Instance.DateTimeNow;
    bool allowLargeReports = (this.processedLargeReports < Settings.Default.LargeReportLimit);
    var reportOrderNextInQueue = this.ReportOrderLogic.GetNextReportOrderAndLock(
        currentDateTime.AddHours(
        this.timeoutValueInHoursBeforeReleaseLock), 
        reportSize, 
        CorrelationIdForPickingReport, 
        allowLargeReports);

    if (reportOrderNextInQueue.IsProcessing)
    {
        Interlocked.Increment(ref this.processedLargeReports);                
    }

    var currentReport = this.GetReportToBeWorked(reportOrderNextInQueue);

    var works = this.WorkTheReport(reportOrderNextInQueue, currentReport, currentDateTime);
    if (reportOrderNextInQueue.IsProcessing)
    {
        Interlocked.Decrement(ref this.processedLargeReports);                
    }
    return works;           
}

“reportOrderNextInQueue”变量从数据库获取报告顺序并检查报告顺序是“正常”还是“大”(这是通过定义 reportOrderNextInQueue 变量的 bool IsProcessing 属性实现的)。如果是大型报告,系统随后会互锁递增 processedLargeReport int 并处理大型报告。处理大型报告后,系统联锁会递减该值。

整个想法是我一次只允许处理一个报表,所以一旦一个线程正在处理一个大报表,其他线程就不能访问数据库中的一个大报表。 bool allowLargeReport 变量检查 processedLargeReports int 和是否超出限制。

我很好奇这是否是正确的实现方式,因为我无法在星期一之前对其进行测试。我不确定我是必须使用 InterLocked 类还是只将 processedLargeReports 变量定义为 volatile 成员。

最佳答案

假设您有 5 个线程开始运行上面的代码,并且 LargeReportLimit 为 1。它们将全部读取 processedLargeReports 为 0,allowLargeReports 对它们而言将为真,并且它们将同时开始处理 5 个项目,尽管您的限制为 1。所以如果我理解正确的话,我真的看不出这段代码是如何实现你的目标的。

稍微扩展一下:您读取 processedLargeReports 然后操作(使用它来检查您是否应该允许处理报告)。你表现得好像这个变量不能在阅读和行动之间改变,但事实并非如此。在您读取变量和对变量执行操作之间,任何数量的线程都可以使用 processedLargeReports 做任何事情,因为您没有锁定。在这种情况下互锁只会确保 processedLargeReports 在所有线程处理完所有任务后始终为 0,仅此而已。

如果您需要限制对某些资源的并发访问 - 只需为此使用适当的工具:Semaphore 或 SemaphoreSlim 类。创建允许 LargeReportLimit 线程进入的信号量。在处理报告之前,等待您的信号量。如果达到并发线程处理报告的数量,这将阻塞。处理完成后,释放信号量以允许等待线程进入。这里不需要使用 Interlocked 类。

关于c# - 在 .NET 中使用 Interlocked 类进行多线程处理的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32671042/

相关文章:

c# - 作为 Web 引用(而非服务引用)使用时增加超时

c# - 如何让 SingleOrDefault 通过引用从列表中返回对象?

c# - 多个线程并发访问队列

python - 如何在 Python 中使用多个但数量有限的线程来处理列表

c# - 如何区分两个列表并获得净变化

c# - "Runtime Version"和 "Version"有什么区别?

c# - Distinct() 是否保留始终取列表中的第一个元素

.net - 抛出了 'System.OutOfMemoryException' 类型的异常

multithreading - 嵌套循环中的并行代码

c++ - 从非托管 dll 中的 QThread 回调到托管 C++ 主线程