1. 程式人生 > >【Nim】執行緒記憶體模型

【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後,子執行緒引用的記憶體區域已經失效,而子執行緒也不知道主執行緒將變量回收了,引發了資料異常。

相關資料: