我正在编写的程序是一个游戏服务器,它将在单独的线程中有多个会话。为避免不必要的锁定等待时间,添加了[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;
}
}
我需要验证;
async
/ Task
创建的工作线程不会有单独的ThreadStatic
实例。所以锁是必要的。lock
中的限制是await
无法使用lock
。因此,在lock
中使用async function
是安全的。lock (r)
r
个实例,可以吗?我查看的官方文档和其他代码仅为object
创建了其他lock
。
醇>
答案 0 :(得分:2)
显示的代码是(过度)线程安全且不正确(可以生成相同/同步的随机值)。
ThreadStatic保证每个线程(从线程池中手工创建)都有自己的变量实例。因此,只要您不将该变量暴露在外(如代码中所示),您就不需要lock
。
每个时刻的每个线程只能运行一个函数 - 无论它是传递给线程的async
方法还是函数的一部分。线程不会在执行过程中在函数之间切换,因此不能同时在同一个线程上对GetNext
进行两次调用。
请注意,快速创建多个Random
对象可导致Random number generator only generating one random number - 检查此特定answer以正确初始化此类每线程实例Random
(使用增量种子)
答案 1 :(得分:1)
也许更好的模式是反转问题并让调用者将新的Random()对象的实例传递到依赖于它的代码中。这将保证每个任务的Random的唯一实例,并且更具声明性和可测试性(通过IRandom并在单元测试中使用测试替代将是最好的整体解决方案。) - 对于单元测试,您需要可预测的结果,不是随机结果,因此通过IOC将已知数字生成器替换为随机数生成器的能力非常重要。