• ベストアンサー

DLLはアドレスを共有する?

 CでWindowsプログラミングの勉強をしています.そこでDLLについての質問なのですが,ある本で「DLLは複数のプログラムが共有し,ひとつのDLLはひとつしかメモリ上に配置されない」という文章を読みました.プログラムはDLLの配置されてあるアドレスを元に,DLL内の関数を実行するのだと考えれば納得はいきましたが,よく考えたらおかしいと思いました.  それは「変数,関数」の取り扱いはどうなるのか,ということです.C言語で物理メモリアドレスを見る方法がわからないので何とも言えませんが,試しに,DLL内に次のような関数MyFunctionを用意し,このDLLを取り込むプログラムを同時に2つ走らせ,MyFunctionを何度も呼んでDll1_Variableの値を増加させていきました. LIBSPEC int MyFunction(LPCWSTR str) { static int Dll1_Variable=0; Dll1_Variable++; _tprintf(_T("%d\n"),Dll1_Variable); return 0; }  もしDLLが共有されているのならば,Dll1_Variableの値は2つのプログラムから同時に更新されると思うのですが,実際には2つのプログラム上でまったく独立(つまり各プログラムごとに1,2,3,...というように)増加していきました.こうなるとDLLって本当に共有されているのかという,不信感が出てきてしまいます.  なんだか重大な勘違いをしている気がしてなりませんが,上記のプログラムがなぜ独立に変数が増加していくのか,「DLLが共有される」というのは実際にはどういう仕組みになっているのか,ご存知の方がいらっしゃったらご教授ください.わかりにくい質問ですみません.よろしくお願いします.

noname#129397
noname#129397

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

Win32(要するにNTとか、95以降の奴)ではコードの共有をどのようにしていたか(していないか)は ちょっと忘れてしまいましたが、データ部分については、特に指定しない限りは プロセスごとに独立した空間が割り当てられます。 ですので質問の例にあるように、カウンタは独立して増えることになります。 DLL 内のデータをアプリケーションまたはほかの DLL と共有する方法 http://msdn.microsoft.com/ja-jp/library/h90dkhs0.aspx 参考までに、Win16(Windows 3.1とか)の場合は、 プログラムコードはまるっきり共有されますが、 データ部分はこれもプロセスごとになります。 #コード→CSレジスタで示す領域 #データ→DSレジスタで示す領域

noname#129397
質問者

お礼

なるほど,コードの共有は行ってもデータについては個々に持っているということですね.よくわかりました.ありがとうございます.

その他の回答 (2)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

>スレッドの場合も個々にデータを保持しているのでしょうか. これは、特に指定しない限りは、同じプロセスに属するスレッドであれば 全く同じデータを共有します。 なので、 > スレッドの場合は何か特別な事情が生じてくることはあるのでしょうか. まさしくこのとおりです。 スレッド ローカル ストレージ (TLS: Thread Local Storage) http://msdn.microsoft.com/ja-jp/library/6yh4a9k1.aspx

noname#129397
質問者

お礼

なるほど,スレッドの場合は気をつけなければならないということですね.よく理解できました.ありがとうございます.

  • wolf03
  • ベストアンサー率22% (241/1086)
回答No.2

プログラムがロードされる領域と変数が使う領域は別物だからです。

noname#129397
質問者

お礼

そうですよね.単純な事実にまったく気がつきませんでした. ところで,これに共有に関してさらに疑問に思ったこととして,マルチスレッドの状況で複数のスレッドがDLLを共有するとどうなるのでしょう?スレッドは確かメモリ空間を共有するという話を聞きましたが,スレッドの場合も個々にデータを保持しているのでしょうか. 「スレッドセーフ」という言葉もあることですし,スレッドの場合は何か特別な事情が生じてくることはあるのでしょうか.

関連するQ&A

  • Delphi6 DLL内でのメモリ共有(?)

    こんにちは、honiyonです。  複数アプリケーションからそれぞれコールバック関数を登録してもらい、状況に応じてそれぞれのコールバック関数を呼び出す、というDLLを作成しています。  しかし現在、呼び出しアプリケーションごとにメモリ空間が独立してしまい、コールバック情報を同一空間内で管理出来ずに困っています。  旧VerのDelphiで16bit DLLなら、interface部に定義した変数、オブジェクトはDLL内で同一空間内で共有出来るようですが、これをDelphi6 32bitDLLで行う事は不可能でしょうか? もしくは、その他の方法で独立メモリ空間を作らないようにする方法はありますでしょうか?  不可能な場合、CreateFileMappingが次に有効な手段として候補に挙がると思います。CreateFileMappingで管理クラスのポインタを渡してクラス共有というのは現実的な手法でしょうか?  よろしくお願いいます(..

  • DLLのマルチスレッドの動作について

    今、DLLについて勉強しているのですが動作について、不明点があり質問しています。 単純にDLL内に下記のようにMyFuncという関数があったとします。 (コンパイルは/MTを付けています) MyFunc (){ int i; for(i=0;i<10;i++){ printf("%d\n"); } } これをDLLを呼び出すアプリから複数のスレッドで呼び出したとき、それぞでのスレッド毎に、カウントが増えていきます。 DLLはメモリ共有されると思っているのですが、そうではないのか、いまいちわからない状態でご教授いただければと思っています。 このカウントが別々に増えるのは、コードの領域とデータの領域が別ベルだからと考えればよいのでしょうか? コードは同じ領域を使用して、データは別の領域を使用しているのでしょうか? 次にここで使用しているint iをグローバル変数にすると、カウントはスレッド毎に共有されてしまいます。 グローバル変数にすると、この場合のint iはコードの領域に置かれるということなんでしょうか? ちょっと、的を得ていない質問かもしれませんが、何卒、よろしくお願いいたします。

  • DLLの共有メモリと排他処理???

    共有メモリを持つDLLを作りました 機能は単純です (1)カウンターをアップしてその値を返す ⇒ CountUp() (2)カウンターの現在値を返す ⇒ TotalCount() #pragma data_seg(".HShared") static int m = 0; #pragma data_seg() #pragma comment(linker,"/Section:.HShared,rws") int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, PVOID pvReserved) { return TRUE; } EXPORT int CALLBACK CountUP() { m++; return m; } EXPORT int CALLBACK TotalCount() { return m; } このDLLは多数のアプリから呼ばれます 当然同時に呼ばれることもあるでしょう カウンター m には排他処理を施してありません 大丈夫でしょうか? それとも排他は Windows様 がしてくれているのでしょうか? 色々と調べてみましたが良く分かりません 宜しくご教授お願い申し上げます

  • DLLについて

    MFCを含むVC++で作られた関数をCで使えるようなDLLを作成しています。 MFC_FUNCTION→DLL(C)→exe(C) windowsXP上では、動作するのですがwindows2000上では下記エラーがでます。 「The variable "iRet" is being used without being defined」 ここで"iRet"はMFC_FUNCTIONで使われている変数です。 このエラーをなくしたいのですが、どうすればいいか教えて下さい。

  • Cで自作したDLLをへC#から文字配列を渡したい

    CでDLLを自作したのですが、その引数にchar**型があるのですが、C#から使用するときにどの型の変数を渡せばいいのかわかりません。 色々と調べていくつか同じような事例があったのですが、うまくいきません。 Cで作ったDLLは __declspec(dllexport) int DetectComPorts(LPWORD ComPortTable, int ComPortMax, char **ComPortDesc) です。この中で「char **ComPortDesc」が問題です。 Cで書いたプログラムからはこのDLLが使用できることを確認しています。 Cの場合はchar**型の適当な変数を作ってmallocでメモリ確保してこの関数に渡して実行するとちゃんとアドレスに目的の文字列が格納されて帰ってきます。 よろしくお願いします

  • DLLのプロパティ値の非共有

    VBで作成したDLLのプロパティ共有 すみません。DLL作成初心者です。 VBでDLLを作成してみたんですが、Original.Exeから呼び出した Called_A.DLLをそのままに、Called_B.DLLをOriginal.Exeから呼び出しました。 そこで、Called_B.DLLからもCalled_A.DLLを呼び出す事が出来るのですが、 Called_B.DLLから呼び出したCalled_A.DLLのプロパティを変更したところ、 Original.Exeから呼び出したCalled_A.DLLのプロパティの値も変更されているんです。 DLLってのは、インスタンスをあっちこっちで作ることができ、各々で作ったインスタンス内で 閉じられているもんだと思っていました。 作り方で共有する事が出来たり、各々で閉じたりそうなっちゃうんですか? ダイナミックリンクライブラリっていう位だから、各々で閉じる事は出来ないんですかね? メモリを共有するのとかしないとかが絡んでいるのかなと思いましたが、ヘルプをみても よく分からないし、その手のDLLについて書いてあるサイトを見てみたんですが、 いまいちよく分からず的を得ているのか得てないのかすら分かりません。 すみませんが、どなたかご教授お願いします。 相関図) 1-1: Original.Exe → 1-2: Called_A.DLL ↓ 2-1: Called_B.DLL → 2-2: Called_A.DLL ※何故か2-2で設定したプロパティが1-2のプロパティにも反映されている... 環境: WindowsXP Professional VisualBasic6(SP5) InternetExplolor6

  • "main"について

    "main"についての質問です。 今まで私は"main"というのはC言語の予約語の一つだと思い込んでいましたので、"main"は変数名には使えないと思っていました。 ところが以下のようなプログラムを実行してみると問題なくコンパイル出来る上に問題なく実行できました。 int main(void) { int main; main = 300; printf("%d\n", main); return 0; } 確かに入門書などを見直してみると、予約語の中に"main"はありませんでしたし、関数名が変数名として使えないとは書いて無いように思います。 でもなんだかしっくりきません。(^^;) 関数ポインタを使う際などは、変数=関数名(p = myfunction)などと書いたりするので、main関数が格納されているメモリなど変なところを書き換えたりしている可能性があるような気がしたのですが、うまく確認する方法を思いつきませんでした・・・。 ただたんに変数が優先的に処理されているだけというのなら納得するしかないのですが。 どなたか詳しい方がいたら教えてください。よろしくお願いします。

  • 関数内、ファイルのstatic変数

    関数内で、static変数を宣言した場合に、その値は保持されると 思いますが、その関数の外からポインタで見る場合にその値は 保証されるのでしょうか? (必ず同じメモリ上に配置されるのでしょうか?) また、関数とファイル内static変数においてスコープ以外に 取り扱いが変わったりするのでしょうか? (配置されるメモリ空間等) よろしくお願い致します。

  • VS2010C#からのDLL使用について

    VS2010 C#からVC6で作成したDLLへint配列を引数として渡したい。 VC++6で作成されたDLLがあります。 ここで定義されている int test(char*fname,int* x,int* y); ファイルのフルパスを渡すと 返り値が関数の成否のコードを返す。 処理内で x,y にファイルから読み込んだ値が それぞれ上限100個としてセットして返す といったような関数を C#から呼び出したいのですが 1 [DllImport("dll名", EntryPoint = "test", CallingConvention = CallingConvention.Cdecl)] public unsafe static extern int test(IntPtr fname, ref int* x,ref int* y); 2 [DllImport("dll名", EntryPoint = "test", CallingConvention = CallingConvention.Cdecl)] public unsafe static extern int test(IntPtr fname, ref IntPtr x,ref IntPtr y); と2種類の呼び出し方法をこころみました。 ファイルのフルパスは IntPtr fnamePtr = Marshal.StringToHGlobalAnsi(string型ファイルフルパス); としております。 1の場合は int[] resX = new int[100]; int[] resY = new int[100]; fixed(int* x= resX) fixed(int* x= resY) として呼び出そうとすると : エラー CS1657: '固定変数' であるため、'x' を ref または out 引数として渡せません となり失敗してしまいます。 2 で試みた場合 int size = sizeof(int)*100; IntPtr x = Marshal.AllocHGlobal(size); IntPtr y = Marshal.AllocHGlobal(size); と引き渡したところ ビルドは通りますが 実行時に System.AccessViolationException' のハンドルされていない例外が 発生しました。 追加情報: 保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。 となってしまいます。 どのようにすれば思惑通りの結果を得られますでしょうか。

  • DLLの利用について

    現在、VCで作成したDLLをVB使うということを行っています。 概要は、VBの方で定義した配列に1~9の数字を代入し、その和を求めるというものです。 DLLに値を渡す際は参照による引渡しをし、DLLで変数の変更を行いたいんです。 しかしその変数の変更がうまくいかないんです。 どこがまずいのでしょうか? プログラム内容は以下に示します。 よろしくお願いします。 *****VBのプログラム***** Option Explicit Private Declare Sub Sum Lib "test.dll" (aa, bb) Private Sub Command1_Click() Dim a(9) As Integer  '1~9の値の代入先 Dim b As integer   '和 Dim I As Integer For I = 0 To 9 a(I) = I + 1 Next I b = 0 Sum a, b  'DLLでの計算 MsgBox (b) '結果表示 End Sub *****DLLの中身***** _declspec(dllexport) void _stdcall Sum(short *aa, short bb) { int i; for ( i=0; i<=9; i++){ bb=bb+aa[i]; } } *****モジュール定義内容***** EXPORTS Sum

専門家に質問してみよう