2017-05-30 14 views
0

要するに、私は次のことを達成しようとしていました。たくさんのことを効果的に管理したいと思っています(数十億ドル/高速で処理するための配列を作成し、スレッドにすぐに物を渡さないと、配列は非常に大きくなり、必要に応じてデータをJNIに渡し、ベクトルに格納する必要があるスレッドのsegfaultsが発生します。 、ベクトルマネージドJNIスレッドを作成する[C++]

最初の1であることを、私はすべてが同時にJNIを実行すると、Javaがクラッシュした約45スレッド以上を起動しようとした場合:

は、私は2つの問題に直面してきました。彼らは同時にすべてを実行していない場合、それは正常に動作しますが、私はそれが何かに影響を与えるように見えないほどのメモリを取得していないというGCからの多くの苦情を得る。

2番目は、私が現時点でのスピードでスレッドを生成すると、私が管理して後でそれらに参加するベクトルが大きくなりすぎるということです。

結論として、私はかなり時間を犠牲にせずに作成しているスレッドを追跡するための速い方法が必要です。

//g++ -std=c++11 -I/usr/lib/jvm/java-8-openjdk/include -I/usr/lib/jvm/java-8-openjdk/include/linux cpptest/Test.cpp -L/usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server -ljvm -lpthread 
#include <jni.h> 
#include <iostream> 
#include <thread> 
#include <string.h> 
#include <vector> 
#include <chrono> 
#include <mutex> 
#include <fstream> 
#include <algorithm> 

jclass cls; 
jmethodID mid; 
JNIEnv* env; 
JavaVM* jvm; 
std::mutex m; 

typedef struct { 
    long seed; 
    int chunkX; 
    int chunkZ; 
    int eyes; 
} Stronghold; 

void ThreadFunc(Stronghold strhld, std::ofstream *outfile) { 
    jvm->AttachCurrentThread((void**)&env, NULL); 
    jlongArray rt = (jlongArray)env->CallStaticLongMethod(cls, mid, (jlong)strhld.seed, (jint)strhld.chunkX, (jint)strhld.chunkZ, (jint)strhld.eyes); 
    jsize size = env->GetArrayLength(rt); 
    std::vector<long> rtVec(size); 
    env->GetLongArrayRegion(rt, 0, size, &rtVec[0]); 
    jvm->DetachCurrentThread(); 
    std::string write; 
    m.lock(); 
    for(long &element : rtVec) { 
     write = std::to_string(element) + "; "; 
    *outfile << write; 
    } 
    *outfile << std::endl; 
    m.unlock(); 
} 

int main(int argc, char* argv[]) { 
    std::ofstream outfile("./new.txt",std::ofstream::binary); 
    std::vector<std::thread> threads; 

    const int kNumOptions = 3; 
    JavaVMOption options[kNumOptions] = { 
    { const_cast<char*>("-Xmx512m"), NULL }, 
    { const_cast<char*>("-verbose:gc"), NULL }, 
    { const_cast<char*>("-Djava.class.path=/home/jewe37/Desktop/"), NULL } 
    }; 

    JavaVMInitArgs vm_args; 
    vm_args.version = JNI_VERSION_1_8; 
    vm_args.options = options; 
    vm_args.nOptions = sizeof(options)/sizeof(JavaVMOption); 

    env = NULL; 
    jvm = NULL; 
    JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &vm_args); 

    const char* kClassName = "Processor"; 
    cls = env->FindClass(kClassName); 
    if (cls == NULL) { 
    std::cerr << "FINDCLASS" << std::endl; 
     return 1; 
    } 

    const char* kMethodName = "ProcessSeed"; 
    mid = env->GetStaticMethodID(cls, kMethodName, "(JIII)[J"); 
    if (mid == NULL) { 
    std::cerr << "FINDMETHOD" << std::endl; 
     return 1; 
    } 

    Stronghold strhld; 

    for(int i = 0; i < std::stoi(argv[1]); i++) { 
     strhld = {i, i*2, i*3, i*4}; 
     threads.emplace_back(ThreadFunc, strhld, &outfile); 
     std::this_thread::sleep_for(std::chrono::microseconds(50)); 
    } 

    std::cout << threads.size() << std::endl; 

    for (std::thread &thread : threads) if (thread.joinable()) thread.join(); 

    jvm->DestroyJavaVM(); 

    outfile.close(); 
    return 0; 
} 
+2

あなたがスレッドプールを探しているようですね。新しいスレッドを作成するのは比較的高価ですが、あなたはそれを狂ってしまいます。さらに、スレッドを実行するための実行リソースを持つよりも多くの並行スレッドを持つことは、通常役に立ちません。また、有害な可能性があります。とにかく、私はあなたの仕事の実際の実行よりもはるかに先んじることの価値を見ません。それらを束縛されたキューに入れてください。スレッドを生成しているスレッドがあまりにも先に進んだらブロックするようにしてください。実際のジョブを実行するためのリソースを解放するという追加の利点があります。 –

+0

@JohnBollingerこの数多くのスレッドを持つことは、〜350usごとに入ってくる他の計算の出力に対処する最良の選択肢のように思えました。私は間違いなくスレッドを使用する必要があります。なぜなら、残りの部分を残しておくために、これを分離する必要があるからです。スレッドプールが私の特定のケースで動作するかどうかを確認します。 – JeWe37

+0

あなたのベクトルが大きくなっているので、あなたのタスクの実行がその世代に追いついていないことを示唆しています。スレッドプールの作成と結合のオーバーヘッドを取り除くことで(スレッドプールを使用して)それが役に立ちますが、十分ではない場合、深刻な問題が発生する可能性があります。 –

答えて

0

スレッド間でJNIEnvを共有することはできません。スレッド単位でなければなりません。 envをThreadFunc()にローカルにする。この質問は完全にhereと答えています。また、ネイティブスレッドを終了する前にデタッチすることを忘れないでください。

関連する問題