2012年12月30日日曜日

共有ライブラリを複数のプロセスから呼び出した場合のグローバル変数の振る舞い

共有ライブラリはロードしたプログラムデータはプロセス間で共有するが、インスタンスはプロセス毎に持つことを確認してみました。
実験はプロセスAとプロセスBが共有のライブラリTest.dllを参照して、グローバル変数を変更します。

ここはグローバル変数をインスタンス化して、このインスタンスのGetterとSetterをインターフェイスにして公開します。

プロセスAとBが参照するTest.dllの中身
///
/// Test.h
///
#ifndef _INC_TEST_H_
#define _INC_TEST_H_

#ifdef _TEST
 #define TEST_API __declspec(dllexport)
#else
 #define TEST_API __declspec(dllimport)
#endif

namespace Test {

TEST_API void SetValue(int val);
TEST_API int GetValue();

}

#endif

///
/// Test.cpp
///
#include "Test.h"

namespace Test {

///
/// プロセス間のメモリ共有の確認
/// プロセス毎に初期化が行われ、プロセス毎にインスタンスが生成される
///
static int _val = 0;

TEST_API int GetValue()
{
 return _val;
}

TEST_API void SetValue(int val)
{
 _val = val;
}

}

暗黙的リンクでTest.dllをロードします。エントリポイントのはじめにTest空間にあるグローバル変数の値を2に変更し、プロセスBを実行します。そのあとにグローバル変数を確認します。表示される値は2か100のどちらかになると思います。2であれば、グローバル変数のインスタンスが共有されていることになります。100であれば、プロセス毎にインスタンスが生成されていることになります。

プロセスAのエントリポイント
///
/// AMain.cpp
///
#include "Test.h"
#include <iostream>
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
 // 初期値の表示
 std::cout << "A.exe " << Test::GetValue() << std::endl;

 // 値を2に更新
 Test::SetValue(2);

 // 別プロセスを実行
 // 別プロセスで値を100に更新している
 system("B.exe");

 // 値の表示
 std::cout << "A.exe " << Test::GetValue() << std::endl;

 return 0;
}

プロセスBのエントリポイント
///
/// BMain.cpp
///
#include "Test.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
 // 値の表示
 std::cout << "B.exe " << Test::GetValue() << std::endl;

 // 値を100に更新
 Test::SetValue(100);

 return 0;
}

出力結果
A.exe 0
B.exe 0
A.exe 2

結果からプロセス毎にインスタンスが生成されていることが分かりますね。

0 件のコメント:

コメントを投稿