Mobile native

[UI Sample] Ecore Thread 2 Sample Overview

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

The sample uses 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_sync() function for applying thread-safe. The thread moves a button (Evas object) by using the evas_object_move() function.

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

Figure: Ecore Thread 2 screen

Ecore Thread 2 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_sync() function is used with the thread_safe_call_sync_cb() callback. The thread_safe_call_sync_cb() callback is in the critical section, to make threads safe for the main loop.

#include <pthread.h>

static pthread_t thread_id;
static Eina_Bool thread_finish = EINA_FALSE;

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

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

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

   // Return value passes to ecore_main_loop_thread_safe_call_sync() return value
   return NULL;
}

static void *
thread_run(void *arg)
{
   Evas_Object *btn = arg;
   double t = 0.0;
   Evas_Coord x, y;
   
   while (!thread_finish) 
   {
      x = 150 + (150 * sin(t));
      y = 200 + (150 * cos(t));

      user_data data;
      data.btn = btn;
      data.x = x;
      data.y = y;
      ecore_main_loop_thread_safe_call_sync(thread_safe_call_sync_cb, &data);
      usleep(1000);
      t += 0.001;
   }

   pthread_exit(NULL);

   return NULL;
}

static void
win_del_cb(void *data, Evas_Object *obj, void *event_info)
{
   void *thread_result;
   thread_finish = EINA_TRUE;
   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_del_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_sync()
   Evas_Object *btn;

   // Create a button
   btn = elm_button_add(ad->conform);
   elm_object_text_set(btn, "Thread<br>Safe<br>Sync");
   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