【Nim】线程内存模型

在Nim的设计中,每一个线程都有自己一个独立的heap,这意味着在多个线程之间不能引用同一个变量,带来的好处是不会出现竞态条件(race condition),坏处也很明显,多线程之间无法共享变量。

让我们来看个简单的例子感受一下。为了引入多线程,我安装了第三方库winim(几乎涵盖了所有的windows api,非常棒)

import winim/lean

echo "Main Thread: ", GetCurrentThreadId()

type
    MyObj = ref object
        x: int

proc free(this: MyObj) =
    this.x = -1
    echo "Free"

proc builder(): MyObj =
    new(result, free)
    result.x = 5

var obj = builder()
echo "Main Thread: x = ", obj.x

proc threadProc(param: LPVOID): DWORD {.stdcall.} =
    echo "Child Thread: ", GetCurrentThreadId()
    var b = obj   # 引用主线程的变量
    echo "Child Thread: x = ", b.x
    Sleep(3000)   # 在这期间obj已经被主线程释放了
    echo "Child Thread: x = ", b.x

CreateThread(nil, 0, LPTHREAD_START_ROUTINE(threadProc), nil, 0, nil)
# 暂停一下,要不然线程还没执行
Sleep(1000)

obj = nil
GC_fullCollect()

Sleep(5000)
echo "Bye"

运行结果如下:

Main Thread: 7364
Main Thread: x = 5
Child Thread: 10440
Child Thread: x = 5
Free
Child Thread: x = -1
Bye

在主线程中手动回收对象后,特地将成员变量x置为-1,然后子线程前后两次输出结果不同。

正是因为主线程感知不到子线程引用了其维护的变量,导致主线程在GC之后子线程引用的内存区域同时失效,而子线程又不知道主线程将变量回收了,从而引发了数据异常。

相关资料:

https://nim-lang.org/docs/manual.html#threads

你可能感兴趣的:(Nim)