2017-05-30 49 views
0

總之,我一直在努力完成以下任務:我希望能夠有效地管理很多(數十億/他們不需要很長時間就能完成,但我是創建數組以進行高速處理,如果我不馬上將東西傳遞給線程,數組變得非常大以至於導致段錯誤),這些線程在必要時將數據傳遞給JNI,並且需要存儲在向量中。創建矢量管理的JNI線程[C++]

我一直面臨兩個問題:

第一個是,如果我試圖產卵比約45線程都同時運行JNI,Java的崩潰了。如果他們沒有在同一時間運行,它可以正常工作,但我從GC得到很多抱怨,說它沒有獲得足夠的內存,儘管這似乎沒有影響任何內容。

第二個是,如果我以我現在的速度產生線程,那麼我用來管理和稍後加入它的向量會變得太大。

因此,總而言之,我需要一種快速的方式來跟蹤我創建的線程,而不會犧牲任何時間。

//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。另外,不要忘記在退出之前分離您的本地線程。