0

我一直threadpool在 Nim 中使用,并且遇到了spawned 函数不能接受可变参数的要求。但是,我想传递一个 proc a Lock,它又必须是可变的,根据acquire. 我发现解决这个问题的唯一方法是让锁可变并在全局范围内声明,所以我不必将它传递给函数 I spawn

但我真的宁愿避免这种情况。我有使用指针的想法——所以锁可以是可变的,但指针本身不是——来解决这个问题,但看起来指针在 Nim 中并不是真正的一流对象。我尝试只是将参数声明waitLock为(第 3 行),但我仍然收到必须在此处传递 a而不是 aref的抱怨。而且看起来取消引用指针也是自动完成的,所以没有办法解决它......?有什么办法可以绕过使用动态范围并将锁显式传递给proc?我不能做我想做的事有充分的理由吗?还是我只是错过了某些手册中的取消引用运算符?实现这一点的最干净的方法是什么?acquirevar Lockref Lock

import os, threadpool, locks

proc waitLock(lock: ref Lock): void =
  acquire lock
  echo "Child thread has lock!"
  release lock

var lock: Lock
initLock lock

spawn waitLock(lock)
acquire lock
echo "Parent thread has lock!"
release lock

sync()
deinitLock lock
4

1 回答 1

0

实现这一点的最干净的方法是什么?

使用全局锁。确实,当全局变量减少封装并使代码更难推理时,它们被认为是糟糕的风格,但是像 Channels、Locks 和 Thread 对象这样的东西在语义上是全局的,所以恕我直言,这些批评并不适用

我不能做我想做的事有充分的理由吗?

是的。线程改变参数本质上是不安全的,因此 Nim 通常禁止将 var 参数传递给线程是正确的。

为什么这与变异全局有什么不同?

Nim 的内存模型有点不同。引用手册:

每个线程都有自己的(垃圾收集)堆,内存共享仅限于全局变量。这有助于防止竞争条件。GC 效率提高了很多,因为 GC 永远不必停止其他线程并查看它们引用的内容。

这也意味着 GC 对象(任何包含refstring或的东西seq)不能在线程之间传递,即使是全局的或包装在 Channel 或 SharedList 中。安全地从经过的渠道
中引用:

请注意,当通过指针(例如通过线程的参数)将对象传递给另一个线程上的过程时,使用默认分配器创建的对象将使用线程本地、GC 管理的内存。因此,将通道对象存储在全局变量中通常更安全(如上例所示),在这种情况下,它们将使用进程范围(线程安全)的共享堆。

但是,可以使用例如 system.allocShared0 为通道手动分配共享内存,并通过线程参数传递这些指针

使用--gc:orc/时这个限制被解除--gc:arc,新的Isolated允许子图在线程之间的安全无复制移动。使用此机制的 Channels 的新实现将在下一个版本中(无论是 1.4.6 之后的版本)

指针并不是真正的一流对象......没有办法取消引用指针......我只是错过了取消引用运算符吗?

虽然 Nim 鼓励使用ref(跟踪引用)以确保安全和轻松,但作为一种系统语言,课程指针(未跟踪引用)是完全支持的。

要从可变对象获取未跟踪的引用,请使用addr,并且取消引用 a 的语法与 aptr相同ref[]

您忽略的手册内容在这里

这是您示例中的语法:

import os, threadpool, locks

proc waitLock(lock: ptr Lock): void =
  acquire lock[]
  echo "Child thread has lock!"
  release lock[]

var lock: Lock
initLock lock

spawn waitLock(lock.addr)
acquire lock
echo "Parent thread has lock!"
release lock

sync()
deinitLock lock
于 2021-05-06T17:23:35.103 回答