1

I want to update A volatile FLAG value of java from C using JNI and i am doing some processing based on the changed FLAG value in java.The code uploaded works fine if I don't call the callit function using thread.It works fine for else clause where i am calling it as a normal function. But when i call this function using thread it crashes.and its happening at the line where i am trying to get the Jclass object.

        #include <jni.h>
        #include<stdio.h>
        #include "JNIDemoJava.h"
        #include "Bridge.h"
        #include<malloc.h>
        #include<time.h>
        #include<pthread.h>
        #include<math.h>
        float Data_Q[8192*8192];
        float Data_I[8192*8192];
        float Data_Q1[8192*8192];
        float Data_I1[8192*8192];


        struct send_data

        {

            float *data;

            int index;

           const char *fname;

        }*a,*b;





        struct call_it

        {

        const char* fname1;

        const char *fname2;

        int ind;

        int scale_factor;

        float *Parameter;

        float *Data_I;

        float* Data_Q;

        int* Data_out;

        JNIEnv * jenv;

        jobject jobj;

        }



        JNIEXPORT jintArray JNICALL Java_jnidemojava_Main_nativePrint(JNIEnv  * env,jobject obj, jstring s1, jstring s2,jint ind,jint scale_factor,jfloatArray Params,jintArray jdata,jfloatArray DataI,jfloatArray DataQ,jobject job)

        {

                jintArray arr;

                pthread_t thread1,thread2,thread3;

                int i=0,t1=0,t2=0,t3=0,indx=0;

                jclass cls = (*env)->GetObjectClass(env,obj);

                int *data = (*env)->GetIntArrayElements(env,jdata,NULL);

            int * adata = (*env)->GetDirectBufferAddress(env,job);

            float *Parameters = (float*)malloc(sizeof(float)*13);
            Parameters = (*env)->GetFloatArrayElements(env,Params,NULL);

            const char *fname1,*fname2;

            fname1 = (*env)->GetStringUTFChars(env,s1,NULL);

            fname2 = (*env)->GetStringUTFChars(env,s2,NULL);

            printf("Value of ind = %d",ind);

            for(indx=0;indx<ind;indx++)

            {

            struct call_it  *asd= (struct call_it*)malloc(sizeof(struct call_it));

            asd->ind =   indx;

            asd->Data_I = Data_I;

            asd->Data_Q= Data_Q;

            asd->fname1= fname1;

            asd->fname2  = fname2;

            asd->scale_factor = scale_factor;

            asd->Data_out = adata;

            asd->Parameter = Parameters;

            asd->jenv = env;

            asd->jobj = obj;


            if(Parameters[12] ==1)

            {



        a= (struct send_data *)malloc(sizeof(struct send_data));

        b= (struct send_data *)malloc(sizeof(struct send_data));
        a->index = b->index = indx;

        a->data = Data_I;

        b->data = Data_Q;

        a->fname = fname1;

        b->fname = fname2;

        t1= pthread_create(&thread1, NULL, maini, (void*) a);

        t2= pthread_create(&thread2, NULL, mainq, (void*) b);

        pthread_join(thread1,NULL);

        memcpy(Data_I1,Data_I,sizeof(float)*8192*8192);

        pthread_join(thread2,NULL);

        memcpy(Data_Q1,Data_Q,sizeof(float)*8192*8192);

        asd->Data_I = Data_I1;

        asd->Data_Q = Data_Q1;

        t3= pthread_create(&thread3, NULL, callit, (void*) asd);
        //pthread_join(thread3,NULL);

            }

            else

            {

                 callit(asd);

            }


            free(asd);

            free(a);

            free(b);

            }

            return arr;





        }



        void*  callit(void *b) {

           struct call_it *asd = (struct call_it*)b;



            JNIEnv *env=asd->jenv;

            jobject obj= asd->jobj;

            jclass cls = (*env)->GetObjectClass(env,obj);//crashes at this point


            jfieldID fidnum = (*env)->GetStaticFieldID(env,cls,"FLAG","I");

            if(fidnum==NULL)

                {

                    printf("-----------_Error________________");

                    return;

                }

                jint num = (*env)->GetStaticIntField(env,cls,fidnum);



            process_data(b);



              num =asd->ind;

             (*env)->SetStaticIntField(env,cls,fidnum,num);



        }

As per my understanding it should work fine for both the cases.if not then there must be some limitation with c threads, which i need to take care.I want the code to work for both calls as a function and a thread .

  • Possible duplicate of [How to obtain JNI interface pointer (JNIEnv \*) for asynchronous calls](https://stackoverflow.com/questions/12900695/how-to-obtain-jni-interface-pointer-jnienv-for-asynchronous-calls) (Note that the second answer seems to be more relevant than the accepted answer.) – prl Mar 25 '19 at 14:54

1 Answers1

0

I cannot specifically explain why your native method appears to be failing at the GetObjectClass call, but more generally, your native method is deeply flawed. Specifically,

The JNI interface pointer is only valid in the current thread. A native method, therefore, must not pass the interface pointer from one thread to another.

(JNI Specifications, chapter 2)

You are doing precisely what that provision forbids. A native method may create new native threads (though I don't recommend it) but only the one in which the JVM invoked the native method may access the JNI environment pointer in any way, for any reason.

That issue could be enough to explain your observed behavior, but even if the true explanation were something else, it's not really worthwhile looking deeper at this point, because the native method needs a wholesale rewrite, and perhaps even a redesign.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thank you @John Bollinger now i understand why its not working with the thread. But i just want to ask is there any way from which we can modify the JAVA variable from C threads.. Actually i want these tasks to run in parallel thats why i used threading. Otherwise without threading it works fine. – Vikas Singh Mar 25 '19 at 12:15
  • @VikasSingh, code in a native method manipulates Java objects *only* via the JNI environment, and that can be done only by the thread in which the VM invokes the method. You may launch additional native threads to perform a computation in parallel, but any inputs read from Java objects and any results stored in Java objects must be transferred between Java and native by the one thread permitted to manipulate the JNI environment. – John Bollinger Mar 25 '19 at 12:49
  • @VikasSingh, I have not analyzed your computation in any depth, but perhaps you'll find that it works better to narrow the scope of the native method to just the work of a single worker thread, so that you can perform the thread management on the Java side. – John Bollinger Mar 25 '19 at 12:51
  • @John, JNI is not as limited as you have said. The way to do this is described here: https://stackoverflow.com/a/12900986 – prl Mar 25 '19 at 14:52
  • @prl thanx for the link that really helped me – Vikas Singh Mar 27 '19 at 04:51