问题很简单,但我相信解决方案(如果存在的话)非常复杂。 无论如何,我目前正在开发一个分布式应用程序,它应该通过使用线程并行实现简单的事务处理(PRINT,ADD,SLEEP,ASSIGN等)(我使用Pthreads进行此分配)。正如预期的那样,我在尝试同时处理多个冲突事务(可能高达20的事务)时遇到了死锁问题。
现在,我决定为每个线程的事务处理实现一些重试,这些重试基本上是使用srand(time(NULL))
和rand()
随机调用的。问题是,当处理多个事务时(在多达5个不同的服务器上),数字匹配,因为它们基本上是在同一秒内生成的。
所以,我的问题是,有没有办法完全随机生成不使用time()
函数的整数,而是使用其他东西?
提前感谢您提供任何帮助,并对(太长)的描述感到抱歉。
答案 0 :(得分:1)
要在不同的线程之间拥有独立的伪随机生成器PRG,您必须更加小心。基本上,您必须将生成器的状态保存在每个线程的单独变量中,并使用每个线程不同的内容初始化每个状态一次。例如,使用时间和线程ID进行初始化。
由于你在POSIX系统上,你可以jrand48
作为生成器函数,但任何允许你将状态作为参数传递的随机生成器应该没问题。
答案 1 :(得分:0)
在每次致电srand()
之前,您不应该致电rand()
。这是问题的根本原因。相反,在创建线程之前,应该在程序启动时只调用srand()
一次。
此外,rand()
不需要在POSIX上是线程安全的,因此您应该使用互斥锁从不同的线程序列化对它的访问。
答案 2 :(得分:0)
正如您所观察到的,当几个PRNG以相同的值播种时,使用PRNG计算退避和重试时间不起作用。如果冲突是破坏性的,那么两个会话将使用相同的重试时间并继续无限期地相互抵消。
如果这只是在一台计算机上运行的一个任务多线程应用程序,那么您可以尝试将线程ID用作PRNG种子。
如果分发可能比单个任务更广泛,那么最终会遇到将所有唯一标识符组合成一个唯一标识符的问题,该标识符适合种子值的大小。虽然独立线程的数量可能足够少,但是可预测的唯一变换可能是困难的。
也许作为每个线程启动的一部分,您应该连接到竞争资源并获取唯一的会话ID。如果你可以错开不同线程的启动,那么你就不必处理争用(只是在第一个线程确认它有自己的ID之前拒绝启动另一个线程)。如果这是不可能的(例如,在广泛分布的情况下),您将必须从其他随机源计算重试时间,例如/dev/urandom
。
但是,如果只能同时处理n
个n
个请求之一,则此问题可以自行解决。
在n-1
个并发请求中,一个客户端获得其响应并继续,而{{1}}必须重试。不成功的客户将提升他们的PRNG状态,其他人则不会。如果他们都有相同的PRNG状态,那么他们都会再次竞争,但是一个人会通过,其他人会再次尝试。最终所有人都将通过冲突(逐个),并将拥有独特的PRNG状态。