Creating and terminating native threads at Android NDK

This recipe discusses how to create and terminate native threads at Android NDK.

Getting ready…

Readers are expected to know how to create an Android NDK project. We can refer to the Writing a Hello NDK program recipe in Chapter 1, Hello NDK, for detailed instructions.

How to do it...

The following steps describe how to create a simple Android application with multiple native threads:

  1. Create an Android application named NativeThreadsCreation. Set the package name as cookbook.chapter6.nativethreadscreation. Refer to the Loading native libraries and registering native methods recipe in Chapter 2, Java Native Interface for more detailed instructions.
  2. Right-click on the project NativeThreadsCreation, select Android Tools | Add Native Support.
  3. Add a Java file named MainActivity.java under package cookbook.chapter6.nativethreadscreation. This Java file simply loads the native library NativeThreadsCreation and calls the native jni_start_threads method.
  4. Add mylog.h and NativeThreadsCreation.cpp files under the jni folder. The mylog.h file contains the Android native logcat utility functions, while the NativeThreadsCreation.cpp file contains the native code to start multiple threads. A part of the code is shown next.

    The jni_start_threads function starts two threads and waits for the two threads to terminate:

    void jni_start_threads() {
      pthread_t th1, th2;
      int threadNum1 = 1, threadNum2 = 2;
      int ret;
      ret = pthread_create(&th1, NULL, run_by_thread, (void*)&threadNum1);
      ret = pthread_create(&th2, NULL, run_by_thread, (void*)&threadNum2);
      void *status;
      ret = pthread_join(th1, &status);
      int* st = (int*)status;
      LOGI(1, "thread 1 end %d %d", ret, *st);
      ret = pthread_join(th2, &status);
      st = (int*)status;
      LOGI(1, "thread 2 end %d %d", ret, *st);
    }

    The run_by_thread function is executed to the native threads:

    int retStatus;
    void *run_by_thread(void *arg) {
      int cnt = 3, i;
      int* threadNum = (int*)arg;
      for (i = 0; i < cnt; ++i) {
        sleep(1);
        LOGI(1, "thread %d: %d", *threadNum, i);
      }
      if (1 == *threadNum) {
        retStatus = 100;
        return (void*)&retStatus;
      } else if (2 == *threadNum) {
        retStatus = 200;
        pthread_exit((void*)&retStatus);
      }
    }
  5. Add an Android.mk file in the jni folder with the following code:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := NativeThreadsCreation
    LOCAL_SRC_FILES := NativeThreadsCreation.cpp
    LOCAL_LDLIBS := -llog
    include $(BUILD_SHARED_LIBRARY)
  6. Build and run the Android project, and use the following command to monitor the logcat output:
    $ adb logcat -v time NativeThreadsCreation:I *:S

    The following is a screenshot of the logcat output:

    How to do it...

How it works...

This recipe shows how to create and terminate threads at Android NDK.

Build with pthreads

Traditionally, pthread is implemented as an external library and must be linked by providing a linker flag -lpthread. Android's Bionic C library has its own pthread implementation bundled in. Therefore, we do not use -lpthread in the Android.mk file in our project.

Thread creation

As demonstrated in our code, a thread can be created with the pthread_create function, which has the following prototype:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

This function creates and starts a new thread with attributes specified by the attr input argument. If attr is set to NULL, default attributes are used. The start_routine argument points to the function to be executed by the newly created thread with arg as the input argument to the function. When the function returns, the thread input argument will point to a location where the thread ID is stored and the return value will be zero to indicate success, or other values to indicate error.

In our sample code, we created two threads to execute the run_by_thread function. We pass a pointer to an integer as input argument to the run_by_thread function.

Thread termination

The thread is terminated after it returns from the start_routine function or we explicitly call pthread_exit. The pthread_exit function has the following prototype:

void pthread_exit(void *value_ptr);

This function terminates the calling thread and returns the value pointed by value_ptr to any successful join with the calling thread. This is also demonstrated in our sample code. We called pthread_join on both threads we created. The pthread_join function has the following prototype:

int pthread_join(pthread_t thread, void **value_ptr);

The function suspends the execution of the calling thread until the thread specified by the first input argument terminates. When the function returns successfully, the second argument can be used to retrieve the exit status of the terminated thread as demonstrated in our sample code.

In addition, the logcat screenshot that we have seen previously shows that calling return from a thread is equivalent to calling pthread_exit. Therefore, we can get the exit status when either method is called.

Note

pthread_cancel is not supported by Android Bionic C library pthread. Therefore, if we are porting code which uses pthread_cancel, we will need to refactor the code to get rid of it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset