Windowsの動的ライブラリ(DLL)中のグローバル変数を複数のプロセスで利用する方法とそのグローバル変数の寿命についてまとめました.
DLLでデータを共有する方法
DLLのデータセグメントに置かれた変数は複数のプロセスで共有可能です. なので data_seg pragma を使用して明示的にデータセグメントに変数を配置することでプロセスをまたいだ変数の参照をすることが出来ます.
ただし初期値を設定しないとBSS領域に置かれてしまうので、必ず初期化もするようにしましょう.
また、セクション名は任意につけることが出来ます.
DLLで共有したデータの寿命
検証用に以下のDLLとexeを作りました.
exeはwhileループで終了しないようにしています.
// 検証用DLL #include<stdio.h> #pragma comment( linker, "/SECTION:.shared,RWS" ) #pragma data_seg( ".shared" ) /* セクション名は任意でok */ int g_var = 0; /* 初期化しないとBSS領域に置かれてしまうので注意 */ #pragma data_seg() BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" __declspec(dllexport) void print() { printf("g_var:%d", ++g_var); }
// 検証用exe #include <iostream> #include<Windows.h> int main() { HINSTANCE hApp; void(*func)(); hApp = LoadLibrary(L"dll1.dll"); func = (void(*)())GetProcAddress(hApp, "print"); func(); while (1) { Sleep(1000); } }
検証用のexeを起動すると、以下のような結果が得られました(2024/3/6更新)
# exe1つ目起動 g_var:1 # exe2つ目起動(1つ目はwhileループ中) g_var:2 # exe3つ目起動(1つ目をkill後) g_var:3 # 検証用exeをすべてkillしたのちに3つ目起動 g_var:1
以上から、DLLで共有したデータの寿命は DLLをロードしたプロセスがすべて終了するまで のようです.
また、 バイナリ一致するDLLもパスが違えば別物扱いされます . つまり変数を共有できるのはパスも含めて同じDLLを利用しているプロセスに限ります.