Mobile native

[UI Sample] Ecore Thread 3 Sample Overview

The Ecore Thread 3 sample demonstrates how you can design threads to work together with the Ecore main loop by considering asynchronization and mutual exclusion.

The sample uses the pthread functions, such as pthread_create() for creating a thread and pthread_exit() for exiting the thread. It also uses the ecore_main_loop_thread_safe_call_async() function for applying thread-safe. The thread moves a button (Evas object) by using the evas_object_move() function.

The ecore_main_loop_thread_safe_call_async() function call is returned immediately, like "Fire and Forgot". The ecore_main_loop_thread_safe_call_async() function has no thread blocking, since its callback is queued and performed asynchronously, whereas ecore_main_loop_thread_safe_call_sync() does have blocking.

The following figure illustrates the main screen of the Ecore Thread 3 sample app.

Figure: Ecore Thread 3 screen

Ecore Thread 3 screen

Implementation

The create_base_gui() function creates the window which consists of a button (Evas object). It also creates a thread by using the pthread_create() function.

A parameter of the pthread_create() function is the thread_run() callback. In the thread_run() callback, the ecore_main_loop_thread_safe_call_async() function is used with the thread_safe_call_async_cb() callback. The thread_safe_call_async_cb() callback is in the critical section, to make threads safe for the main loop.

#include <pthread.h>

static pthread_t thread_id;
static pthread_mutex_t lock;
static Eina_Bool thread_finish = EINA_FALSE;

typedef struct user_data 
{
   Evas_Object *btn;
   Evas_Coord x, y;
} user_data;

static void
thread_safe_call_async_cb(void *data)
{
   // This function is in critical section

   user_data *ud = data;
   evas_object_move(ud->btn, ud->x, ud->y);
}

static void *
thread_run(void *arg)
{
   Evas_Object *btn = arg;
   double t = 0.0;
   Evas_Coord x, y;

   while (1) 
   {
      x = 150 + (150 * sin(t));
      y = 200 + (150 * cos(t));

      user_data data;
      data.btn = btn;
      data.x = x;
      data.y = y;
      // Now no need to wait for synchronizing main loop here
      ecore_main_loop_thread_safe_call_async(thread_safe_call_async_cb, &data);
      usleep(1000);
      t += 0.001;

      // Mutual exclusive for shared data
      pthread_mutex_lock(&lock);
      if (thread_finish) break;
      pthread_mutex_unlock(&lock);
   }

   pthread_exit(NULL);

   return NULL;
}

static void
win_del_cb(void *data, Evas_Object *obj, void *event_info)
{
   void *thread_result;

   // Mutual exclusive for shared data
   pthread_mutex_lock(&lock);
   thread_finish = EINA_TRUE;
   pthread_mutex_unlock(&lock);

   pthread_join(thread_id, &thread_result);
   elm_exit();
}

static void
create_base_gui(appdata_s *ad)
{
   // Window
   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
   elm_win_autodel_set(ad->win, EINA_TRUE);

   if (elm_win_wm_rotation_supported_get(ad->win)) 
   {
      int rots[4] = { 0, 90, 180, 270 };
      elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
   }

   // evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
   eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);

   // Conformant
   ad->conform = elm_conformant_add(ad->win);
   elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
   elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
   evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   elm_win_resize_object_add(ad->win, ad->conform);
   evas_object_show(ad->conform);

   // ecore_main_loop_thread_safe_call_async()
   Evas_Object *btn;
   evas_object_smart_callback_add(ad->win, "delete,request", win_del_cb, NULL);

   // Create a button
   btn = elm_button_add(ad->conform);
   elm_object_text_set(btn, "Thread<br>Safe<br>Async");
   evas_object_resize(btn, 150, 200);
   evas_object_show(btn);

   // Create a thread
   if (!pthread_create(&thread_id, NULL, thread_run, btn))
   perror("pthread_create!\n");

   // Show the window after the base GUI is set up
   evas_object_show(ad->win);
}
Go to top