【发布时间】:2013-08-28 19:55:29
【问题描述】:
我正在使用 C 语言开发一个 Wa-tor 模拟器,它的要求非常严格,我对如何在具有相同参数的调用之间正确获得可重现的行为有点困惑。
Wa-tor 基本上是一个 2D 细胞阵列,只能包含水,一条鱼或一条鲨鱼。
我所拥有的是(我将尝试仅列出对理解问题感兴趣的内容):
- 一个配置文件,用户可以在其中指定一个整数种子,以及其他选项
- 一个主进程,它解析配置文件并产生(fork+execve)用户请求的尽可能多的工作子进程。此外,它将收集所有工作人员的状态,将其显示为一个大网格。 Worker 通过 UNIX 套接字文件与 master 通信。
- 许多多线程 (pthreads) 工作进程。
Workers 连接到主套接字并接收模拟参数,包括用户指定的种子(此时种子在添加worker ID 的worker 之间是有区别的。Worker ID 是一个渐进的数字,master 可重复地分配给worker 并包含在 execve 的命令行中,因此 worker 可以在连接到 master 的套接字时识别并每次分配到相同的网格部分。
Worker 随机初始化其 subgrid 并将其发送给 master,然后从相邻的 worker 接收/发送边界值。
Worker 的状态从现在开始以离散的步骤演变,称为 chronon。在每个步骤中,worker 为其子网格中的每个生物计算一个随机动作,然后与相邻的 worker 和 master 交换更新。
一个线程监听信号,而另一个例程处理“模拟”部分。这个模拟例程 - 在每一步结束时 - 产生 4 个其他线程以向相邻线程发送更新,4 个用于接收更新,1 个用于向主线程发送状态。在开始另一个步骤之前,此线程将在以后加入。
我目前正在做的处理随机数的生成是拥有一个全局“unsigned int SEED”,它提供了在工作进程开始时从主服务器接收到的值(在任何线程之前)产生),并使用“extern”关键字包含在我需要它的每个文件中。所以我在调用“rand_r(&SEED)”时使用它的地址。
第一个问题是调用 rand_r 后 SEED 的值没有更新,因为我可以观察到运行单线程应用程序。我忘记了什么?
然后我问一个全局变量是否是获得可重现序列的正确方法,承认 rand_r 可以被不同的线程调用,并且动作序列可能会随着工作人员之间的通信不遵循而改变严格的顺序,-如果不是这样,从一个整数值作为种子开始?要求是,从相同的确切参数和种子开始,两次执行一步一步地产生相同的结果(就像任何受人尊敬的模拟器一样,我猜 :)
附:我正在考虑改用 drand48_r() 但汤是一样的,我猜。
问候 博士
【问题讨论】:
-
SioulSeuguh 给了你正确的想法,我想。但是您另外切换到
drand48家族的想法当然也是一个好主意。你不需要_r,这里erand48、jrand48和nrand48是接收状态作为参数的版本。 -
@SioulSeuguh 阅读 [e,j,n]rand48 的手册和各自的 _r 可重入版本,我不能完全确定不可重入的不使用全局随机生成器状态。该人说不可重入函数采用的
unsigned short xsubi[3]用作“连续Xi值的存储”,但我认为存储在全局状态中的其他值用于计算随机值。上瘾的人_r 版本明确表示“他们没有修改全局随机生成器状态,而是使用提供的数据缓冲区”struct drand48_data *
标签: c multithreading random pthreads