質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C++/CLI

C++/CLIは、.NET Frameworkの共通言語基盤であるCLI向けにC++を拡張したプログラム言語です。前身のC++マネージ拡張と比較するとシンプルで分かりやすい構文になっており、高い可読性を持ちます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

7612閲覧

スレッド間のグローバル変数の共有

tkym_1231

総合スコア57

C++/CLI

C++/CLIは、.NET Frameworkの共通言語基盤であるCLI向けにC++を拡張したプログラム言語です。前身のC++マネージ拡張と比較するとシンプルで分かりやすい構文になっており、高い可読性を持ちます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/05/13 15:11

前提

c++/CLIを用いて、マルチスレッド処理を行うアプリを作成しています。
環境はVisual Studio 2019です。

質問

以下のようなdllを作成して、スレッド1とスレッド2でそれぞれでクラスをnewした後、
スレッド1でProc1をコールし、
スレッド2でProc2をコールした場合、
グローバル変数iRequest はスレッド間で共有されますか?

c++

1int iRequest = 0; 2 3namespace Wrapper 4{ 5 public ref class WrapperClass 6 { 7 //スレッド1で呼ぶ 8 int Wrapper::WrapperClass::Proc1() 9 { 10 return iRequest; 11 } 12 13 //スレッド2で呼ぶ 14 int Wrapper::WrapperClass::Proc2() 15 { 16 iRequest++; 17 return iRequest; 18 } 19 } 20}

上記のコードを動かしたときに、スレッド1ではiRequestは0のままで、スレッド2ではインクリメントされた値が帰ってくると考えていたのですが、予想に反してスレッド1でもインクリメントされた値が返ってきました。
自分はスレッド毎に別のアドレス空間だと思っていたのですが、そうではないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

既出の通り、メモリ空間を共有するのがスレッド、共有しないのがプロセスとなります
(他にもハンドルを基本的に共有しませんが)

共有したくないグローバル変数ならばthread_localにするという手があります。

c++11
c++/cli
msvc

投稿2021/05/13 16:56

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkym_1231

2021/05/14 01:22

各言語の仕様のページを教えていただき、ありがとうございます。 勉強になりました。
guest

0

読み取るタイミングによって結果が変わりますから、それを保証したい場合は性能を犠牲にロックを取る必要があります。C++/CLIのようなので、SemaphoreSlimとかを使います。また、今回変数の型がintだからいいですが、long型とかクラス型とかだと、いわゆるアトミック性の問題が出てきますので何かしらのロックは必要です(Interlocked::IncrementとかSemaphoreSlimとか)

以下はSemaphoreSlimをとりあえず使ってみる用例です。C++らしいRAIIをかんたんにするライブラリとかはlambda式のcaptureにC++/CLIのハンドルを渡せないという問題から古典的な全手動でRAIIクラスを作る必要があります(C++/CLIのベストプラクティスに詳しくないのでもうちょいまともな解決策ありそう)

cpp

1//RAII class 2ref class SemaphoreSlimGuard 3{ 4 SemaphoreSlim^ sem; 5 SemaphoreSlimGuard(SemaphoreSlimGuard^ sem, int maxCount) 6 : sem(nullptr) 7 { 8 if (sem->CurrentCount != maxCount) return; 9 this->sem = sem; 10 this->sem->Wait(); 11 } 12 ~SemaphoreSlimGuard() 13 { 14 try 15 { 16 sem->Release(); 17 } 18 catch(Exception^ e){} 19 } 20 !SemaphoreSlimGuard() 21 { 22 this->~SemaphoreSlimGuard(); 23 } 24 explicit operator bool() { return this->sem != nullptr; } 25} 26

cpp

1static const int max_count = 1; 2static SemaphoreSlim^ sem = gcnew SemaphoreSlim(1, max_count); 3... 4 5{ 6 SemaphoreSlimGuard guard(sem, max_count); 7 //なにかのグローバル変数に対する操作 8} 9// C++/CLIのデストラクタはC#でいうところのIDisposableなので、スコープを抜けるとデストラクタが呼ばれ、セマフォのカウントが戻る

投稿2021/05/13 21:02

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkym_1231

2021/05/14 01:25

詳細な説明と例をありがとうございます。排他処理の方法について参考にさせていただきます。
guest

0

スレッド間では同じメモリ空間を用います。

メモリ空間は1つの「プロセス」ごとに割り当てられます。
「スレッド」は1つの「プロセス」内に複数存在することができ、それらは並列に動くことができます。

スレッド間で値を共有する方法としてグローバル変数を用いるのはよくある手段です。

投稿2021/05/13 16:12

編集2021/05/13 16:14
rinjinto

総合スコア170

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkym_1231

2021/05/14 01:23

回答をありがとうございます。スレッドとプロセスの関係について理解出来ました。
guest

0

グローバル変数はスレッド間で共有されます。

投稿2021/05/13 16:08

hide5stm

総合スコア426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tkym_1231

2021/05/14 01:23

簡潔な回答をありがとうございます。理解出来ました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問