【问题标题】:Is this StaticRandom class thread-safe?这个 StaticRandom 类是线程安全的吗?
【发布时间】:2018-04-07 06:19:48
【问题描述】:

我正在编写的程序是一个游戏服务器,它将在单独的线程中有多个会话。为了避免不必要的锁等待时间,添加了[ThreadStatic]

该程序将包含一些异步函数和 ThreadSafeStaticRNG(这个类)将在异步中使用。

public class ThreadSafeStaticRNG 
{
    [ThreadStatic]
    static Random r = new Random();

    /// <summary>
    /// get random number from [min,max)
    /// </summary>
    /// <returns></returns>
    public static int GetNext(int min, int max)
    {
        int n;
        lock (r)
        {
            n = r.Next(min, max);
        }
        return n;
    }
}

我需要验证;

  1. 据我了解,使用async/Task 创建的工作线程不会有单独的ThreadStatic 实例。所以锁是必要的。
  2. 如果以上为真,则lock 中唯一的限制是await 不能在lock 中使用。所以在async function 中使用lock 是安全的。
  3. (编辑)lock (r) 用于r 实例,可以吗?我查看的官方文档和其他代码仅为lock创建了其他object

【问题讨论】:

  • @UweKeim 是的,我进行了研究,但没有明确回答两个问题。这就是为什么我说I need verification,因为信息不是来自官方文件。
  • 我的错,没看清楚你的问题,抱歉。

标签: c# multithreading asynchronous thread-safety


【解决方案1】:

显示的代码(过度)线程安全且不正确(可以生成相同/同步的随机值)。

ThreadStatic 保证每个线程(手动创建或取自线程池)都有自己的变量实例。因此,只要您不将该变量暴露在外部(如您的代码中所示),您就不需要 lock

每个线程在每个时刻只能运行一个函数——无论它是async 方法的一部分还是传递给线程的函数。线程不会在执行过程中在函数之间切换,因此不可能同时在同一个线程上同时对GetNext 进行两次调用。

请注意,快速创建多个Random 对象可能会导致Random number generator only generating one random number - 检查此特定answer 以正确初始化此类每个线程实例Random(使用增量种子)。

【讨论】:

  • 对不起,我没有阅读完整的答案。那么,在这种情况下,async 将拥有独立的RNG,并且锁定是完全没有必要的,对吗?
  • @YukiNyaa 我强烈怀疑您需要阅读 bing.com/search?q=c%23+task+vs+thread... 是的,不需要锁定。 “在这种情况下,异步将有独立的 RNG”没有答案 - 链接搜索应该能够帮助您。
  • 还要注意,OP 对 [ThreadStatic] 的初始化并没有达到预期的效果。请参阅msdn.microsoft.com/en-us/library/…,其中注释指出:不要为标有 ThreadStaticAttribute 的字段指定初始值,因为此类初始化仅在类构造函数执行时发生一次,因此仅影响一个线程。如果不指定初始值,如果是值类型,则可以依赖被初始化的字段为其默认值,如果是引用类型,则可以依赖为 null。
【解决方案2】:
  1. Task/Async可能没有分配给它的单独线程,而一个 Task可能在多个线程上执行。
  2. 是的,使用 Lock 是安全的,并且使用非线程安全的 Random 功能,必须这样做。无需混合 Lock 和 线程静态。在我的使用 Lock() 的意图中更明显 意见,并离开 ThreadStatic。
  3. 创建一个新对象并锁定它是正常的,而不是锁定操作对象,但在您的情况下这样做并没有错。

也许更好的模式是反转问题并让调用者将一个新的 Random() 对象的实例传递给依赖它的代码。这将保证每个任务都有一个唯一的 Random 实例,并且更具声明性和可测试性(通过 IRandom 并在单元测试领域使用测试替代品将是最佳的整体解决方案。) - 对于单元测试,您需要可预测的结果,不是随机结果,因此通过 IOC 将已知数生成器替换为随机数生成器的能力非常重要。

【讨论】:

  • 谢谢。我应该考虑对 RNG 本身使用不同的方法。
猜你喜欢
  • 2011-08-03
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多