DLL内にあるグローバル変数をマルチスレッド間で共有しないようにするには?
- 評価
- クリップ 1
- VIEW 6,794
Java上でOggをJavaからDLLを呼び出すJNA経由で再生するために、Oggファイルを再生するDLLを作ろうと、C++とC言語を組み合わせてDLLを作ったのですが、マルチスレッドだとバグが起き、原因がグローバル変数を用いており、そのグローバル変数がマルチスレッドだと同じ内容が共有されているからだと分かりました。
このグローバル変数をスレッドローカルにしようとしたのですが、コンストラクタとデストラクタがあるクラスでは、スレッドローカルの変数にする事が出来ません
何か良い解決策はありますでしょうか?C++の部分を完全にC言語に書きなおすしかないのでしょうか?
コードは以下の物となります。OggDecorderクラスなどのソースは下記のサイトに有ります。
http://marupeke296.com/OGG_main.html
この質問は下記の質問に関連したものです
https://teratail.com/questions/35915
#include <memory.h>
#include <string>
#include <iostream>
#include "vorbis/vorbisfile.h"
#include "OggDecoder.h"
#include "OggVorbisMemory.h"
#include "OggVorbisFile.h"
#include "PCMPlayer.h"
#include "DixSmartPtr.h"
#include "DixComPtr.h"
#include "OggMain.h"
using namespace std;
Dix::sp< Dix::OggVorbisMemory > spOggResource;
Dix::sp< Dix::OggDecoder > spOggDecoder = Dix::sp< Dix::OggDecoder>(new Dix::OggDecoder(spOggResource));
int check = -1;
extern "C" int OggDll::open(char* filePath)
{
check = -1;
spOggResource = Dix::sp< Dix::OggVorbisMemory > (new Dix::OggVorbisMemory);
if (spOggResource->createBuffer(filePath) == false)
{
check = -1;
return -1;
}
else
{
check = 0;
spOggDecoder = Dix::sp< Dix::OggDecoder>(new Dix::OggDecoder(spOggResource));
spOggDecoder->getSampleRate();
return 0;
}
}
extern "C" void OggDll::close()
{
}
// 指定サイズでPCM音声バッファを埋める関数
extern "C" int OggDll::getPCMBuffer(char* buffer,int bufferSize)
{
bool a = true;
unsigned int b = 100;
if(check==-1)
{
return -1;
}
else
{
spOggDecoder->getSegment(buffer, bufferSize, &b, &a);
return 0;
}
}
// 指定サイズでPCM音声バッファを埋める関数
extern "C" int OggDll::getSampleRate()
{
if (check == -1)
{
return -1;
}
else
{
return spOggDecoder->getSampleRate();
}
}
// 指定サイズでPCM音声バッファを埋める関数
extern "C" int OggDll::getChannel()
{
if (check == -1)
{
return -1;
}
else
{
return spOggDecoder->getChannel();
}
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+5
どのような使い方を想定しているのか判りませんが、あるスレッドでopenしつつ、別のスレッドでもopenしたいということでしょうか。
その場合は、スレッドローカル変数で無理矢理切り分けようとするのではなく、呼び出し側にインスタンスのポインタを返して、そのポインタ経由で各種操作を行うような仕組みにすべきだと思います。C/C++のプログラムと何ら変わりません。
ソースを見る限り、オブジェクトはDix::OggVorbisMemory
とDix::OggDecoder
の二つなので、その二つを構造体でパックして、その構造体をnewしたポインタをJava側に返し、そのポインタ経由で操作するようにすれば良いと思います。そうすればグローバル変数を使う必要はなくなります。
コード例
struct OggHandle
{
Dix::sp<Dix::OggVorbisMemory> spOggResource;
Dix::sp<Dix::OggDecoder> spOggDecoder;
};
extern "C" OggHandle* OggDll::open(char* filePath)
{
OggHandle *handle = new OggHandle;
handle->spOggResource = Dix::sp<Dix::OggVorbisMemory>(new Dix::OggVorbisMemory);
handle->spOggDecoder = Dix::sp<Dix::OggDecoder>(new Dix::OggDecoder(handle->spOggResource));
handle->spOggDecoder->getSampleRate();
return handle;
}
extern "C" void OggDll::close(OggHandle* handle)
{
delete handle;
}
extern "C" int OggDll::getPCMBuffer(OggHandle* handle, char* buffer,int bufferSize)
{
bool a = true;
unsigned int b = 100;
handle->spOggDecoder->getSegment(buffer, bufferSize, &b, &a);
return 0;
}
// 以下略
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
こんにちは。
このグローバル変数をスレッドローカルにしようとしたのですが、コンストラクタとデストラクタがあるクラスでは、スレッドローカルの変数にする事が出来ません
これはどのような方法を試みられたのでしょうか? もし、thread_local指定したのではないのでしたら、このキーワードを付けてみるのも手と思います。C11, C++11以降で使える機能です。
ただ、JNA経由で呼ばれた時もちゃんと動くのか、あまり確信はもてません。外れていたらごめんなさい。
【追記】
#include<iostream>
struct Foo
{
Foo()
{
std::cout << "Foo()\n";
}
~Foo()
{
std::cout << "~Foo()\n";
}
};
__declspec( thread ) Foo gFoo;
// https://msdn.microsoft.com/ja-jp/library/9zxe5aww.aspx
__declspec(thread) struct A {
A(){}
~A(){}
} aa; // C2483 error
__declspec(thread) struct B {} b; // OK
int main()
{
return 0;
}
コマンドラインで、cl ソース.cpp /EHsc
にてコンパイルしたところ、エラーにならず、正常に実行できました。
MinGW(gcc)でも、問題ありませんでした。
コンパイラのバージョンをあげればもしかすると通るかも知れないです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.34%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/05/28 18:41