在 C# 中确保没有锁语句的线程安全

Posted

技术标签:

【中文标题】在 C# 中确保没有锁语句的线程安全【英文标题】:Ensure thread safety without lock statement in C# 【发布时间】:2021-03-21 02:01:34 【问题描述】:

我正在尝试理解多线程,并且我有以下代码,我需要通过获得最终结果 10,000,000 来确保线程安全(通常不使用 lock 语句),但是如果您在 VS 中多次运行以下代码,您获得接近 10,000,000 的不同值但从未达到,因此我需要在不使用 lock 语句的情况下修复此代码。

using System;
using System.Threading;

namespace ConsoleApp1

    class Program
    
        private static int _counter = 0;
        private static void DoCount()
        
            for (int i = 0; i < 100000; i++)
            
                _counter++;
            
        

        static void Main(string[] args)
        
            int threadsCount = 100;
            Thread[] threads = new Thread[threadsCount];

            //Allocate threads
            for (int i = 0; i < threadsCount; i++)
                threads[i] = new Thread(DoCount);

            //Start threads
            for (int i = 0; i < threadsCount; i++)
                threads[i].Start();

            //Wait for threads to finish
            for (int i = 0; i < threadsCount; i++)
                threads[i].Join();

            //Print counter
            Console.WriteLine("Counter is: 0", _counter);
            Console.ReadLine();
        
    

感谢您的帮助。

【问题讨论】:

你试过volatile 吗?如果还不够,您可以使用例如Monitor volatile 还不够,但 System.Threading.Interlocked.Increment() 可以。 无锁编程真的很难正确完成。您应该不惜一切代价避免它 @Blindy 它需要 大量 的专业知识才能知道在多线程程序中何时可以并且不能真正避免锁定,此外还有使用锁定的成本这一事实,在大多数情况下,都不是问题。如果您达到无锁编程的第一个可能性非常,您的程序充满了错误,并且您不会从中获得任何好处,因为锁不会成为瓶颈。至于这个程序中的线程池不同,差异不大可能那么大,即使并行运行,出现bug的时间窗口也不是很大。 @Blindy 人们多久编写一次性能如此重要的“低级库”,以至于他们没有一个位数的纳秒来取出锁?这个数字不是零,但它低。如果您认为这很容易,那么这只是告诉我您不了解它可能出错的所有方式以及使用它时需要考虑的所有事情。如果您有嵌套锁,那么这意味着您有一个非常复杂的情况,即无锁解决方案偶数可能的可能性非常低,如果是这样的话,这远非易事。 【参考方案1】:

您最好先了解线程,然后快速转向为您抽象复杂性的库。

如果您使用 Microsoft 的响应式框架(又名 Rx) - NuGet System.Reactive 并添加 using System.Reactive.Linq; - 那么您可以这样做:

void Main()

    var query =
        from n in Observable.Range(0, 100)
        from x in Observable.Start(() => DoCount())
        select x;
        
    var counter = query.Sum().Wait();
        
    Console.WriteLine("Counter is: 0", counter);
    Console.ReadLine();


private int DoCount()

    int counter = 0;
    for (int i = 0; i < 100000; i++)
    
        counter++;
    
    return counter;

简单多了,结果如下:Counter is: 10000000

【讨论】:

在先学习较低级别之后,值得尝试一下。超级感谢 2 u【参考方案2】:

是的,Interlocked 类函数是实现无锁多线程同步的方法。在您的具体情况下,您需要Interlocked.Increment

【讨论】:

它奏效了,说实话我以前没听说过。 这意味着你是today's 10000中的一员! JAJA,这是个极客

以上是关于在 C# 中确保没有锁语句的线程安全的主要内容,如果未能解决你的问题,请参考以下文章

如何确保Java线程安全?

分布式场景中确保线程安全的解决方案,redis实现分布式锁

如何确保线程安全?

如何确保线程安全?

C#:高效的线程安全队列ConcurrentQueue<T>

C# Monitor:锁定资源