Nim:生成的函数不能有 Var 参数,但要获取的参数必须是 Var
Nim: Spawned Function Cannot Have a Var Parameter, but Argument to acquire Must Be Var
我一直在 Nim 中使用 threadpool
并且遇到了 spawn
ed 函数不能接受可变参数的要求。但是,我想传递一个过程 Lock
,根据 acquire
的类型,它又 有 是可变的。我发现解决这个问题的唯一方法是让锁可变并在全局范围内声明,所以我不必将它传递到函数 I spawn
.
但我真的宁愿避免这种情况。我有使用指针的想法——所以锁可以是可变的,但指针本身不是——来解决这个问题,但看起来指针并不是真正的 first-class Nim 中的对象。我尝试将 waitLock
的参数声明为 ref
(第 3 行),但我仍然收到投诉,认为 acquire
必须传递 var Lock
而不是 ref 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
What would the cleanest way to implement this be?
使用全局锁。确实,当全局变量减少封装并使代码不那么容易推理时,它们被认为是糟糕的风格,但是像 Channels、Locks 和 Thread 对象这样的东西在语义上是全局的,所以恕我直言,这些批评并不适用
Is it with good reason that I can't do what I want?
是的。线程改变参数本质上是不安全的,因此 Nim 通常禁止将 var 参数传递给线程是正确的。
Why is that any different from mutating a global?
Nim 的 memory model 有点不同。引用手册:
Each thread has its own (garbage collected) heap, and sharing of memory is restricted to global variables. This helps to prevent race conditions. GC efficiency is improved quite a lot, because the GC never has to stop other threads and see what they reference.
这也意味着 GC 对象(任何包含 ref
、string
或 seq
的对象)不能在线程之间传递,即使是全局对象或包装在 Channel 中也是如此或共享列表。
引用自 passing channels safely:
Note that when passing objects to procedures on another thread by pointer (for example through a thread's argument), objects created using the default allocator will use thread-local, GC-managed memory. Thus it is generally safer to store channel objects in global variables (as in the above example), in which case they will use a process-wide (thread-safe) shared heap.
However, it is possible to manually allocate shared memory for channels using e.g. system.allocShared0 and pass these pointers through thread arguments
使用 --gc:orc
/--gc:arc
时取消此限制,新的 Isolated
允许在线程之间安全、无复制地移动子图。使用此机制的 Channels 的新实现将在下一个版本中(无论是 1.4.6 之后的版本)
pointers aren't really first-class objects...no way around dereferencing pointers..Have I just missed the dereference operator?
虽然 Nim 鼓励使用 ref
(跟踪引用)以确保安全和方便,但作为一种系统语言,完全支持课程指针(未跟踪引用)。
要从可变对象获取未跟踪引用,您可以使用 addr
,取消引用 ptr
的语法与 ref
相同:[]
您忽略的手册部分是 here
您的示例中使用的语法如下:
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
我一直在 Nim 中使用 threadpool
并且遇到了 spawn
ed 函数不能接受可变参数的要求。但是,我想传递一个过程 Lock
,根据 acquire
的类型,它又 有 是可变的。我发现解决这个问题的唯一方法是让锁可变并在全局范围内声明,所以我不必将它传递到函数 I spawn
.
但我真的宁愿避免这种情况。我有使用指针的想法——所以锁可以是可变的,但指针本身不是——来解决这个问题,但看起来指针并不是真正的 first-class Nim 中的对象。我尝试将 waitLock
的参数声明为 ref
(第 3 行),但我仍然收到投诉,认为 acquire
必须传递 var Lock
而不是 ref 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
What would the cleanest way to implement this be?
使用全局锁。确实,当全局变量减少封装并使代码不那么容易推理时,它们被认为是糟糕的风格,但是像 Channels、Locks 和 Thread 对象这样的东西在语义上是全局的,所以恕我直言,这些批评并不适用
Is it with good reason that I can't do what I want?
是的。线程改变参数本质上是不安全的,因此 Nim 通常禁止将 var 参数传递给线程是正确的。
Why is that any different from mutating a global?
Nim 的 memory model 有点不同。引用手册:
Each thread has its own (garbage collected) heap, and sharing of memory is restricted to global variables. This helps to prevent race conditions. GC efficiency is improved quite a lot, because the GC never has to stop other threads and see what they reference.
这也意味着 GC 对象(任何包含 ref
、string
或 seq
的对象)不能在线程之间传递,即使是全局对象或包装在 Channel 中也是如此或共享列表。
引用自 passing channels safely:
Note that when passing objects to procedures on another thread by pointer (for example through a thread's argument), objects created using the default allocator will use thread-local, GC-managed memory. Thus it is generally safer to store channel objects in global variables (as in the above example), in which case they will use a process-wide (thread-safe) shared heap.
However, it is possible to manually allocate shared memory for channels using e.g. system.allocShared0 and pass these pointers through thread arguments
使用 --gc:orc
/--gc:arc
时取消此限制,新的 Isolated
允许在线程之间安全、无复制地移动子图。使用此机制的 Channels 的新实现将在下一个版本中(无论是 1.4.6 之后的版本)
pointers aren't really first-class objects...no way around dereferencing pointers..Have I just missed the dereference operator?
虽然 Nim 鼓励使用 ref
(跟踪引用)以确保安全和方便,但作为一种系统语言,完全支持课程指针(未跟踪引用)。
要从可变对象获取未跟踪引用,您可以使用 addr
,取消引用 ptr
的语法与 ref
相同:[]
您忽略的手册部分是 here
您的示例中使用的语法如下:
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