[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
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); }