0

So I created a JNI-C++ dll for Microsoft Sapi 5.4. The program executes smoothly. But even if I call the System.exit(int) in the main of the java program, the program still remain running. I'm using netbeans for the java coding. Additionally, the Runtime.getRuntime().addShutdownHook() is never called.

Any pointer why this keeps happening.

UPDATE: the problem is not with the shutdownhook. The problem occurred whenever a pointer is being delete. Whenever the deleteTTS and the destructor call the delete function, the native side just keeps hanging up.

Code snippet:

JavaVM * javaVM;
jobject javaObj;
//different java callback variables
long speechObjId;
std::wstring theString(L"");

bool debug;

CRESpeechLib::CRESpeechLib(){
    init(1);
}

CRESpeechLib::CRESpeechLib(int val){
    init(val);
}

CRESpeechLib::~CRESpeechLib(){
    this->isInit = false;
    print("Calling destructor of " + this->id);
    this->ttsInterface.unload();
    this->ttsInterface.getVoicePt()->SetNotifySink(NULL);
}

void CRESpeechLib::init(int val){
    this->isInit = true;
    this->id = val;
    print("Creating Class: " + this->id);
    this->ttsInterface.load();
}

bool CRESpeechLib::say(const std::string &sentence){
    bool balik = this->ttsInterface.say(sentence);
    return balik;
}

void CRESpeechLib::removeNotify(){
    this->ttsInterface.getVoicePt()->SetNotifySink(NULL);
}

ISpVoice* CRESpeechLib::getVoicePointer(){
    return this->ttsInterface.getVoicePt();
}

JNIEXPORT jboolean JNICALL Java_com_example_MainClass_speak(JNIEnv *env, jobject obj, jlong ptID, jstring str){
    const char *nativeString = env->GetStringUTFChars(str, FALSE);
    std::string temp(nativeString);
    theString = std::wstring(temp.begin(), temp.end());
    jboolean ret;
    CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    ret = pt->say(nativeString);

    env->ReleaseStringUTFChars(str, nativeString);

    return ret;
}

JNIEXPORT jobjectArray JNICALL Java_com_example_MainClass_getVoices(JNIEnv *env, jobject thisObj, jlong ptID){
    jobjectArray ret;
    CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    std::vector<std::string> list = pt->getVoices();
    ret = (jobjectArray) env->NewObjectArray(list.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));

    int i = 0;
    for (std::vector<std::string>::iterator it = list.begin(); it != list.end(); ++it) {
        env->SetObjectArrayElement(ret, i, env->NewStringUTF((*it).c_str()));
        i++;
    }

    return(ret);
}

JNIEXPORT void JNICALL Java_com_example_MainClass_removeNotify(JNIEnv *env, jobject obj, jlong ptID){
    //jboolean ret;
    CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    pt->removeNotify();

    return;
}

JNIEXPORT jlong JNICALL Java_com_example_MainClass_createTTS(JNIEnv *env, jobject obj, jint id){
    //init variables for the JNI callback

    CRESpeechLib *pt = new CRESpeechLib(id);
    return (jlong) pt;
}

JNIEXPORT void JNICALL Java_com_example_MainClass_deleteTTS(JNIEnv *env, jobject obj, jlong ptID){
    print("Delete called");
    CRESpeechLib *pt = (CRESpeechLib *) (ptID);
    pt->removeNotify();
    delete pt;
    delete javaVM;
    env->DeleteGlobalRef(javaObj);
    return;
}

void __stdcall outsideeventFunction(WPARAM wParam, LPARAM lParam){
    //event handling of tts
    return;
}

void wordBoundaryCallback(int start, int end) {
    //call java method wordBoundaryCallback
}

HRESULT WaitAndPumpMessagesWithTimeout(HANDLE hWaitHandle, DWORD dwMilliseconds)
{
    //create the pump message
    return hr;
}

////////////////////////////JAVA CODES///////////////////////////////////
//Assume all native codes are already declared
    public MainClass(){
        this.id = 1;
        addressRef = createTTS(id);
        System.out.println("Class reference: " + addressRef);
        this.attachShutDownHook();
    }

    public MainClass(int id){
        this.id = id;
        addressRef = createTTS(id);
        System.out.println("Class reference: " + addressRef);
        this.attachShutDownHook();
    }

    public void wordBoundaryReach(int start, int end){
        System.out.println("From CB: Start: " + start + "\t\tEnd: " + end);
    }

    public boolean speak(String msg){
        return speak(addressRef, msg);
    }

    public boolean setVoice(String name){
        return setVoice(addressRef, name);
    }

    public void deleteTTS(){
        deleteTTS(addressRef);
    }

    private void attachShutDownHook(){
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                MainClass.this.deleteTTS(addressRef);
                System.out.println("Inside Add Shutdown Hook");
            }
        });
        System.out.println("Shut Down Hook Attached.");
    }

    public static void main(String[] args) {
        MainClass t = new MainClass(1);
        String[] s = (String[])t.getVoices();
        t.setVoice(s[0]);
        if(t.speak("Testing the functionalities from the library. I hope this is fine. Let us try another sentence for the sake of a long speech.")){
            System.out.println("Tapos na. Success");
        }else{
            System.out.println("Tapos na. Failed");
        }
        System.exit(0);
    }
4

1 回答 1

0

So after a couple of days debugging, I now know what the problem is.

Actually, Runtime.getRuntime().addShutdownHook() is called. But the problem is that my destructor never finished cleaning up the pointers. I don't know what the problem is, but I use delete for those pointers. As I scan my destructor, it always hang somewhere where I call the delete function. So what I did is that I use the c++ std::unique_ptr so that my pointers pt just call release. As of now, I don't know what cause the delete function hanging up.

JavaVM * javaVM;
jobject javaObj;
//different java callback variables
long speechObjId;
std::wstring theString(L"");

std::unique_ptr<CRESpeechLib> pt; //pt now is a global

bool debug;

CRESpeechLib::CRESpeechLib(){
    init(1);
}

CRESpeechLib::CRESpeechLib(int val){
    init(val);
}

CRESpeechLib::~CRESpeechLib(){
    this->isInit = false;
    print("Calling destructor of " + this->id);
    this->ttsInterface.unload();
    this->ttsInterface.getVoicePt()->SetNotifySink(NULL);
}

void CRESpeechLib::init(int val){
    this->isInit = true;
    this->id = val;
    print("Creating Class: " + this->id);
    this->ttsInterface.load();
}

bool CRESpeechLib::say(const std::string &sentence){
    bool balik = this->ttsInterface.say(sentence);
    return balik;
}

void CRESpeechLib::removeNotify(){
    this->ttsInterface.getVoicePt()->SetNotifySink(NULL);
}

ISpVoice* CRESpeechLib::getVoicePointer(){
    return this->ttsInterface.getVoicePt();
}

JNIEXPORT jboolean JNICALL Java_com_example_MainClass_speak(JNIEnv *env, jobject obj, jstring str){
    const char *nativeString = env->GetStringUTFChars(str, FALSE);
    std::string temp(nativeString);
    theString = std::wstring(temp.begin(), temp.end());
    jboolean ret;
    //CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    ret = pt->say(nativeString);

    env->ReleaseStringUTFChars(str, nativeString);

    return ret;
}

JNIEXPORT jobjectArray JNICALL Java_com_example_MainClass_getVoices(JNIEnv *env, jobject thisObj){
    jobjectArray ret;
    //CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    std::vector<std::string> list = pt->getVoices();
    ret = (jobjectArray) env->NewObjectArray(list.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));

    int i = 0;
    for (std::vector<std::string>::iterator it = list.begin(); it != list.end(); ++it) {
        env->SetObjectArrayElement(ret, i, env->NewStringUTF((*it).c_str()));
        i++;
    }

    return(ret);
}

JNIEXPORT void JNICALL Java_com_example_MainClass_removeNotify(JNIEnv *env, jobject obj){
    //jboolean ret;
    //CRESpeechLib *pt = (CRESpeechLib *) (ptID);

    pt->removeNotify();

    return;
}

JNIEXPORT void JNICALL Java_com_example_MainClass_createTTS(JNIEnv *env, jobject obj, jint id){
    //init variables for the JNI callback

    //CRESpeechLib *pt = new CRESpeechLib(id);
    pt = std::unique_ptr<CRESpeechLib>(new CRESpeechLib(id));
    return;
}


JNIEXPORT void JNICALL Java_com_example_MainClass_deleteTTS(JNIEnv *env, jobject obj){
    print("Delete called");
    pt.release();
    return;
}

void __stdcall outsideeventFunction(WPARAM wParam, LPARAM lParam){
    //event handling of tts
    return;
}

void wordBoundaryCallback(int start, int end) {
    //call java method wordBoundaryCallback
}

HRESULT WaitAndPumpMessagesWithTimeout(HANDLE hWaitHandle, DWORD dwMilliseconds)
{
    //create the pump message
    return hr;
}

////////////////////////////JAVA CODES///////////////////////////////////
//Assume all native codes are already declared
    public MainClass(){
        this.id = 1;
        addressRef = createTTS(id);
        System.out.println("Class reference: " + addressRef);
        this.attachShutDownHook();
    }

    public MainClass(int id){
        this.id = id;
        addressRef = createTTS(id);
        System.out.println("Class reference: " + addressRef);
        this.attachShutDownHook();
    }

    public void wordBoundaryReach(int start, int end){
        System.out.println("From CB: Start: " + start + "\t\tEnd: " + end);
    }


    private void attachShutDownHook(){
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                MainClass.this.deleteTTS();
                System.out.println("Inside Add Shutdown Hook");
            }
        });
        System.out.println("Shut Down Hook Attached.");
    }

    public static void main(String[] args) {
        MainClass t = new MainClass(1);
        String[] s = (String[])t.getVoices();
        t.setVoice(s[0]);
        if(t.speak("Testing the functionalities from the library. I hope this is fine. Let us try another sentence for the sake of a long speech.")){
            System.out.println("Tapos na. Success");
        }else{
            System.out.println("Tapos na. Failed");
        }
        System.exit(0);
    }
于 2013-08-20T11:00:36.070 回答