Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are JNI functions thread-safe?

I'm trying to use OpenMP to parallelize the process of converting an Array of Java Strings into a C array of strings (char**):

char** convert(JNIEnv *env, jobjectArray jstringArray, int n_threads){

        int n_rows =(*env)->GetArrayLength(env, jstringArray);
        char **cArray = (char **) malloc(n_rows * sizeof(char*));
        int i=0;
        jstring row;

        if(n_threads <= 0 ) n_threads = 1;
        #pragma omp parallel for num_threads(n_threads) private(i, row)
        for (i=0; i<n_rows; i++) {
                  row = (jstring) (*env)->GetObjectArrayElement(env, jstringArray, i);
                  cArray[i] = (char*)(*env)->GetStringUTFChars(env, row, 0);
                  printf("cArray[%d]: %s thread:%d row:%p env:%p jstringArray:%p\n", i, cArray[i], omp_get_thread_num(), row, env, jstringArray);
        }

        return cArray;
}

However, it seems I am running into a race condition when obtaining the jstring rows:

Output for n_threads = 1:

cArray[0]: AA thread:0 row:0x7f5b1c000c90 env:0x7f5b300091f8 jstringArray:0x7f5bb3ffdc38
cArray[1]: BB thread:0 row:0x7f5b1c000c98 env:0x7f5b300091f8 jstringArray:0x7f5bb3ffdc38
cArray[2]: CC thread:0 row:0x7f5b1c000ca0 env:0x7f5b300091f8 jstringArray:0x7f5bb3ffdc38
cArray[3]: DD thread:0 row:0x7f5b1c000ca8 env:0x7f5b300091f8 jstringArray:0x7f5bb3ffdc38

Output for n_threads = 3:

cArray[0]: AA thread:0 row:0x7f434c004050 env:0x7f434800a9f8 jstringArray:0x7f435b8f0c48
cArray[1]: BB thread:0 row:0x7f434c004060 env:0x7f434800a9f8 jstringArray:0x7f435b8f0c48
cArray[2]: **CC** thread:1 **row:0x7f434c004058** env:0x7f434800a9f8 jstringArray:0x7f435b8f0c48
cArray[3]: **CC** thread:2 **row:0x7f434c004058** env:0x7f434800a9f8 jstringArray:0x7f435b8f0c48

The conflicting function seems to be GetObjectArrayElement(), which returns the same reference for two different threads (1 and 2 on the example) and for 2 diferent array indexes (2 and 3).

Is this behaviour inherent to said JNI function, or am I missing something?

like image 421
cppstudy Avatar asked Mar 11 '26 23:03

cppstudy


1 Answers

I've never worked with JNI before, but a rudimentary google search of "JNI thread safety" returned this as its first hit:

The JNI interface pointer (JNIEnv *) is only valid in the current thread. You must not pass the interface pointer from one thread to another, or cache an interface pointer and use it in multiple threads. The Java Virtual Machine will pass you the same interface pointer in consecutive invocations of a native method from the same thread, but different threads pass different interface pointers to native methods.

Hope that helps.

like image 121
Newt Hoenikker Avatar answered Mar 14 '26 12:03

Newt Hoenikker



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!