Document how to use thread with EFL in nice detail for "beginners" who
know already how to use threads (pthread) and then how to use that with EFL. SVN revision: 63641
This commit is contained in:
parent
394d2225cf
commit
c575d2d4c6
|
@ -92,6 +92,18 @@
|
|||
* @ref progressbar_example
|
||||
*
|
||||
* @ref slideshow_example
|
||||
*
|
||||
* @ref efl_thread_1
|
||||
*
|
||||
* @ref efl_thread_2
|
||||
*
|
||||
* @ref efl_thread_3
|
||||
*
|
||||
* @ref efl_thread_4
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -5927,6 +5939,125 @@
|
|||
* @example win_example.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_1 EFL Threading example 1
|
||||
*
|
||||
* You can use threads with Elementary (and EFL) but you need to be careful
|
||||
* to only use eina or eet calls inside a thread. Other libraries are not
|
||||
* totally threadsafe except for some specific ecore calls designed for
|
||||
* working from threads like the ecore_pipe_write() and ecore_thread calls.
|
||||
*
|
||||
* Below is an example of how to use EFL calls from a native thread you have
|
||||
* already created. You have to put the EFL calls inside the critical block
|
||||
* between ecore_thread_main_loop_begin() and ecore_thread_main_loop_end()
|
||||
* which ensure you gain a lock on the mainloop. Beware that this requires
|
||||
* that the thread WAIT to synchronize with the mainloop at the beginning of
|
||||
* the critical section. It is highly suggested you use as few of these
|
||||
* in your thread as possible and probably put just a single
|
||||
* ecore_thread_main_loop_begin() / ecore_thread_main_loop_end() section
|
||||
* at the end of the threads calculation or work when it is done and
|
||||
* would otherwise exit to sit idle.
|
||||
*
|
||||
* For a progression of examples that become more complex and show other
|
||||
* ways to use threading with EFL, please see:
|
||||
*
|
||||
* @ref efl_thread_2
|
||||
*
|
||||
* @ref efl_thread_3
|
||||
*
|
||||
* @ref efl_thread_4
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
* @include efl_thread_1.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_2 EFL Threading example 2
|
||||
*
|
||||
* You can also use ecore_main_loop_thread_safe_call_sync() to call a
|
||||
* specific function that needs to do EFL main loop operations. This call
|
||||
* will block and wait to synchronise to the mainloop just like
|
||||
* ecore_thread_main_loop_begin() / ecore_thread_main_loop_end() will,
|
||||
* but instead you simply provide it the function callback to call instead
|
||||
* of inlining your code.
|
||||
*
|
||||
* @ref efl_thread_3
|
||||
*
|
||||
* @ref efl_thread_4
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
* @include efl_thread_2.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_3 EFL Threading example 3
|
||||
*
|
||||
* Like with ecore_main_loop_thread_safe_call_sync() you can provide a
|
||||
* callback to call inline in the mainloop, but this time with
|
||||
* ecore_main_loop_thread_safe_call_async() the callback is queued and
|
||||
* called asynchronously, without the thread blocking. The mainloop will
|
||||
* call this function when it comes around to its synchronisation point. This
|
||||
* acts as a "fire and forget" way of having the mainloop do some work
|
||||
* for a thread that has finished processing some data and is read to hand it
|
||||
* off to the mainloop and the thread wants to march on and do some more work
|
||||
* while the main loop deals with "displaying" the results of the previous
|
||||
* calculation.
|
||||
*
|
||||
* @ref efl_thread_4
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
* @include efl_thread_3.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_4 EFL Threading example 4
|
||||
*
|
||||
* Now when you want to have a thread do some work, send back results to
|
||||
* the mainloop and continue running but the mainloop controls when the
|
||||
* thread should stop working, you need some extra flags. This is an example
|
||||
* of how you might use ecore_main_loop_thread_safe_call_async() and pthreads
|
||||
* to do this.
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
* @include efl_thread_4.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_5 EFL Threading example 5
|
||||
*
|
||||
* This is the same as @ref efl_thread_4 but now uses the ecore_thread
|
||||
* infrastructure to have a running worker thread that feeds results back
|
||||
* to the mainloop and can easily be cancelled. This saves some code in the
|
||||
* application and makes for fewer problem spots if you forget a mutex.
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
* @include efl_thread_5.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_6 EFL Threading example 6
|
||||
*
|
||||
* You can also use the ecore_thread infrastructure for compute tasks that
|
||||
* don't send feedback as they go - they are one-shot compute jobs and when
|
||||
* done they will trigger the end callback in the mainloop which is intended
|
||||
* to pick up the results and "display them".
|
||||
*
|
||||
* @include efl_thread_6.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page bg_example_01_c bg_example_01.c
|
||||
* @include bg_example_01.c
|
||||
|
@ -6087,3 +6218,39 @@
|
|||
* @include slideshow_example.c
|
||||
* @example slideshow_example.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_1_c EFL Threading example 1
|
||||
* @include efl_thread_1.c
|
||||
* @example efl_thread_1.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_2_c EFL Threading example 2
|
||||
* @include efl_thread_2.c
|
||||
* @example efl_thread_2.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_3_c EFL Threading example 3
|
||||
* @include efl_thread_3.c
|
||||
* @example efl_thread_3.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_4_c EFL Threading example 4
|
||||
* @include efl_thread_4.c
|
||||
* @example efl_thread_4.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_5_c EFL Threading example 5
|
||||
* @include efl_thread_5.c
|
||||
* @example efl_thread_5.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page efl_thread_6_c EFL Threading example 6
|
||||
* @include efl_thread_6.c
|
||||
* @example efl_thread_6.c
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
* @li @ref widgetslist - These are the widgets you'll compose your UI out of.
|
||||
* @li @ref containerslist - These are the containers in which the widgets will
|
||||
* be laid out.
|
||||
*
|
||||
* Also see other generic EFL programming guides:
|
||||
* @li @ref threading
|
||||
*/
|
||||
/**
|
||||
* @page widgetslist Widget list
|
||||
|
@ -290,3 +293,23 @@
|
|||
* @li @ref infralist - These are modules that deal with Elementary as a whole.
|
||||
* @li @ref widgetslist - These are the widgets you'll compose your UI out of.
|
||||
*/
|
||||
/**
|
||||
* @page threading Threading
|
||||
*
|
||||
* You may use threads with EFL, but only in specific ways. If you plan on
|
||||
* using threads it is very important you see the following example guides.
|
||||
* See the following
|
||||
*
|
||||
* @ref efl_thread_1
|
||||
*
|
||||
* @ref efl_thread_2
|
||||
*
|
||||
* @ref efl_thread_3
|
||||
*
|
||||
* @ref efl_thread_4
|
||||
*
|
||||
* @ref efl_thread_5
|
||||
*
|
||||
* @ref efl_thread_6
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -115,7 +115,13 @@ SRCS = \
|
|||
table_example_02.c \
|
||||
menu_example_01.c \
|
||||
thumb_example_01.c \
|
||||
win_example.c
|
||||
win_example.c \
|
||||
efl_thread_1.c \
|
||||
efl_thread_2.c \
|
||||
efl_thread_3.c \
|
||||
efl_thread_4.c \
|
||||
efl_thread_5.c \
|
||||
efl_thread_6.c
|
||||
|
||||
pkglib_PROGRAMS =
|
||||
|
||||
|
@ -217,7 +223,13 @@ pkglib_PROGRAMS += \
|
|||
table_example_02 \
|
||||
menu_example_01 \
|
||||
thumb_example_01 \
|
||||
win_example
|
||||
win_example \
|
||||
efl_thread_1 \
|
||||
efl_thread_2 \
|
||||
efl_thread_3 \
|
||||
efl_thread_4 \
|
||||
efl_thread_5 \
|
||||
efl_thread_6
|
||||
|
||||
# This variable will hold the list of screenshots that will be made
|
||||
# by "make screenshots". Each item in the list is of the form:
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include <Elementary.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
static pthread_t thread_id;
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void *
|
||||
my_thread_run(void *arg)
|
||||
{
|
||||
double t = 0.0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ecore_thread_main_loop_begin(); // begin critical
|
||||
{ // indented for illustration of "critical" block
|
||||
Evas_Coord x, y;
|
||||
|
||||
x = 200 + (200 * sin(t));
|
||||
y = 200 + (200 * cos(t));
|
||||
evas_object_move(rect, x - 50, y - 50);
|
||||
}
|
||||
ecore_thread_main_loop_end(); // end critical
|
||||
usleep(1000);
|
||||
t += 0.02;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
|
||||
static void
|
||||
my_thread_new(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
perror("pthread_attr_init");
|
||||
if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0)
|
||||
perror("pthread_create");
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-1", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 1");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
o = evas_object_rectangle_add(evas_object_evas_get(win));
|
||||
evas_object_color_set(o, 50, 80, 180, 255);
|
||||
evas_object_resize(o, 100, 100);
|
||||
evas_object_show(o);
|
||||
rect = o;
|
||||
|
||||
// create custom thread to do some "work on the side"
|
||||
my_thread_new();
|
||||
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
|
@ -0,0 +1,90 @@
|
|||
#include <Elementary.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
struct info
|
||||
{
|
||||
double x, y;
|
||||
};
|
||||
|
||||
static void *my_thread_mainloop_code(void *data);
|
||||
|
||||
static pthread_t thread_id;
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void *
|
||||
my_thread_run(void *arg)
|
||||
{
|
||||
double t = 0.0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct info *inf = malloc(sizeof(struct info));
|
||||
|
||||
if (inf)
|
||||
{
|
||||
inf->x = 200 + (200 * sin(t));
|
||||
inf->y = 200 + (200 * cos(t));
|
||||
ecore_main_loop_thread_safe_call_sync
|
||||
(my_thread_mainloop_code, inf);
|
||||
}
|
||||
// and sleep and loop
|
||||
usleep(1000);
|
||||
t += 0.02;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
static void
|
||||
my_thread_new(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
perror("pthread_attr_init");
|
||||
if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0)
|
||||
perror("pthread_create");
|
||||
}
|
||||
|
||||
static void *
|
||||
my_thread_mainloop_code(void *data)
|
||||
{
|
||||
struct info *inf = data;
|
||||
evas_object_move(rect, inf->x - 50, inf->y - 50);
|
||||
free(inf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-2", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 2");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
o = evas_object_rectangle_add(evas_object_evas_get(win));
|
||||
evas_object_color_set(o, 50, 80, 180, 255);
|
||||
evas_object_resize(o, 100, 100);
|
||||
evas_object_show(o);
|
||||
rect = o;
|
||||
|
||||
// create custom thread to do some "work on the side"
|
||||
my_thread_new();
|
||||
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
|
@ -0,0 +1,93 @@
|
|||
#include <Elementary.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
struct info
|
||||
{
|
||||
double x, y;
|
||||
};
|
||||
|
||||
static void my_thread_mainloop_code(void *data);
|
||||
|
||||
static pthread_t thread_id;
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void *
|
||||
my_thread_run(void *arg)
|
||||
{
|
||||
double t = 0.0;
|
||||
|
||||
// inside the pthread function lets loop forever incrimenting a time point
|
||||
for (;;)
|
||||
{
|
||||
struct info *inf = malloc(sizeof(struct info));
|
||||
|
||||
if (inf)
|
||||
{
|
||||
inf->x = 200 + (200 * sin(t));
|
||||
inf->y = 200 + (200 * cos(t));
|
||||
// now call a function in the mainloop and pass it our allocated
|
||||
// data that it will free when it gets it
|
||||
ecore_main_loop_thread_safe_call_async
|
||||
(my_thread_mainloop_code, inf);
|
||||
}
|
||||
// and sleep and loop
|
||||
usleep(1000);
|
||||
t += 0.02;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
static void
|
||||
my_thread_new(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
perror("pthread_attr_init");
|
||||
if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0)
|
||||
perror("pthread_create");
|
||||
}
|
||||
|
||||
static void
|
||||
my_thread_mainloop_code(void *data)
|
||||
{
|
||||
struct info *inf = data;
|
||||
evas_object_move(rect, inf->x - 50, inf->y - 50);
|
||||
free(inf);
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-3", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 3");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
o = evas_object_rectangle_add(evas_object_evas_get(win));
|
||||
evas_object_color_set(o, 50, 80, 180, 255);
|
||||
evas_object_resize(o, 100, 100);
|
||||
evas_object_show(o);
|
||||
rect = o;
|
||||
|
||||
// create custom thread to do some "work on the side"
|
||||
my_thread_new();
|
||||
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
#include <Elementary.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
struct info
|
||||
{
|
||||
double x, y;
|
||||
};
|
||||
|
||||
static void my_thread_mainloop_code(void *data);
|
||||
|
||||
static pthread_t thread_id;
|
||||
static pthread_mutex_t th_lock;
|
||||
static int th_exit = 0;
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void *
|
||||
my_thread_run(void *arg)
|
||||
{
|
||||
double t = 0.0;
|
||||
|
||||
// inside the pthread function lets loop forever incrimenting a time point
|
||||
for (;;)
|
||||
{
|
||||
struct info *inf = malloc(sizeof(struct info));
|
||||
int do_exit;
|
||||
|
||||
if (inf)
|
||||
{
|
||||
inf->x = 200 + (200 * sin(t));
|
||||
inf->y = 200 + (200 * cos(t));
|
||||
// now call a function in the mainloop and pass it our allocated
|
||||
// data that it will free when it gets it
|
||||
ecore_main_loop_thread_safe_call_async
|
||||
(my_thread_mainloop_code, inf);
|
||||
}
|
||||
// and sleep and loop
|
||||
usleep(1000);
|
||||
t += 0.02;
|
||||
// in case someone has asked us to cancel - then cacnel this loop
|
||||
// co-operatively (cancelling is co-operative)
|
||||
pthread_mutex_lock(&th_lock);
|
||||
do_exit = th_exit;
|
||||
pthread_mutex_unlock(&th_lock);
|
||||
if (do_exit) break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
|
||||
static void
|
||||
my_thread_new(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_mutex_init(&th_lock, NULL);
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
perror("pthread_attr_init");
|
||||
if (pthread_create(&thread_id, &attr, my_thread_run, NULL) != 0)
|
||||
perror("pthread_create");
|
||||
}
|
||||
|
||||
static void
|
||||
my_thread_mainloop_code(void *data)
|
||||
{
|
||||
struct info *inf = data;
|
||||
evas_object_move(rect, inf->x - 50, inf->y - 50);
|
||||
free(inf);
|
||||
}
|
||||
|
||||
// just test cancelling the thread
|
||||
static void
|
||||
down(void *data, Evas *e, Evas_Object *obj, void *event_info)
|
||||
{
|
||||
pthread_mutex_lock(&th_lock);
|
||||
th_exit = 1;
|
||||
pthread_mutex_unlock(&th_lock);
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-4", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 4");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
o = evas_object_rectangle_add(evas_object_evas_get(win));
|
||||
evas_object_color_set(o, 50, 80, 180, 255);
|
||||
evas_object_resize(o, 100, 100);
|
||||
evas_object_show(o);
|
||||
// new in the examples - we have a mouse down on the blue box cancel
|
||||
// the thread
|
||||
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, down, NULL);
|
||||
rect = o;
|
||||
|
||||
// create custom thread to do some "work on the side"
|
||||
my_thread_new();
|
||||
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#include <Elementary.h>
|
||||
|
||||
static Ecore_Thread *th = NULL;
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
struct info
|
||||
{
|
||||
double x, y;
|
||||
};
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void
|
||||
th_do(void *data, Ecore_Thread *th)
|
||||
{
|
||||
double t = 0.0;
|
||||
|
||||
// inside our "do" function for the ecore thread, lets do the real work
|
||||
for (;;)
|
||||
{
|
||||
struct info *inf = malloc(sizeof(struct info));
|
||||
|
||||
if (inf)
|
||||
{
|
||||
inf->x = 200 + (200 * sin(t));
|
||||
inf->y = 200 + (200 * cos(t));
|
||||
// now we have recorded the timepoint we pass it as feedback
|
||||
// back to the mainloop. it will free it when done
|
||||
ecore_thread_feedback(th, inf);
|
||||
}
|
||||
// and sleep and loop
|
||||
usleep(1000);
|
||||
t += 0.02;
|
||||
// in case someone has asked us to cancel - then cacnel this loop
|
||||
// co-operatively (cancelling is co-operative)
|
||||
if (ecore_thread_check(th)) break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
|
||||
static void // when mainloop gets feedback from worker
|
||||
th_feedback(void *data, Ecore_Thread *th, void *msg)
|
||||
{
|
||||
struct info *inf = msg;
|
||||
evas_object_move(rect, inf->x - 50, inf->y - 50);
|
||||
free(inf);
|
||||
}
|
||||
|
||||
// BONUS (optional): called after th_do returns and has NOT been cancelled
|
||||
static void th_end(void *data, Ecore_Thread *th) { printf("thread ended\n"); }
|
||||
// BONUS (optional): called in mainloop AFTER thread has finished cancelling
|
||||
static void th_cancel(void *data, Ecore_Thread *th) { printf("thread cancelled\n"); }
|
||||
|
||||
// just test cancelling the thread worker
|
||||
static void
|
||||
down(void *data, Evas *e, Evas_Object *obj, void *event_info)
|
||||
{
|
||||
ecore_thread_cancel(th);
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-5", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 5");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
o = evas_object_rectangle_add(evas_object_evas_get(win));
|
||||
evas_object_color_set(o, 50, 80, 180, 255);
|
||||
evas_object_resize(o, 100, 100);
|
||||
evas_object_show(o);
|
||||
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, down, NULL);
|
||||
rect = o;
|
||||
|
||||
// explicitly create ecore thread to do some "work on the side" and pass
|
||||
// in NULL as data ptr to callbacks and true at the end means to actually
|
||||
// make a new thread and not use the thread pool (there is a thread pool
|
||||
// with as many thread workers as there are cpu's so this means you do not
|
||||
// overload the cpu's with more work than you actually have processing
|
||||
// units *IF* your threads do actually spend their time doing actual
|
||||
// heavy computation)
|
||||
th = ecore_thread_feedback_run(th_do, th_feedback, th_end, th_cancel,
|
||||
NULL, EINA_TRUE);
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
|
@ -0,0 +1,164 @@
|
|||
#include <Elementary.h>
|
||||
|
||||
static Evas_Object *win = NULL;
|
||||
static Evas_Object *rect = NULL;
|
||||
|
||||
struct info
|
||||
{
|
||||
Evas_Object *obj;
|
||||
int *pix;
|
||||
};
|
||||
|
||||
// BEGIN - code running in my custom pthread instance
|
||||
//
|
||||
static void
|
||||
mandel(int *pix, int w, int h)
|
||||
{
|
||||
double x, xx, y, cx, cy, cox, coy;
|
||||
int iteration, hx, hy, val, r, g, b, rr, gg, bb;
|
||||
int itermax = 10000;
|
||||
double magnify = 0.02;
|
||||
|
||||
// this mandel calc is run in the worker threads so it's here. it is
|
||||
// just here to calculate something and consume cpu to demonstrate the
|
||||
// ecore thread worker queue. don't pay much attention to the below code
|
||||
magnify += ((double)(rand() % 100) / 100.0) / 4.0;
|
||||
cox = (double)(rand() % 100) / 100.0;
|
||||
coy = (double)(rand() % 100) / 100.0;
|
||||
cox /= (magnify * 3.0);
|
||||
r = rand() % 255; g = rand() % 255; b = rand() % 255;
|
||||
for (hy = 0; hy < h; hy++)
|
||||
{
|
||||
for (hx = 0; hx < w; hx++)
|
||||
{
|
||||
cx = (((float)hx) / ((float)w) - 0.5) / (magnify * 3.0);
|
||||
cy = (((float)hy) / ((float)h) - 0.5) / (magnify * 3.0);
|
||||
cx += cox;
|
||||
cy += coy;
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
for (iteration = 1; iteration < itermax; iteration++)
|
||||
{
|
||||
xx = (x * x) - (y * y) + cx;
|
||||
y = (2.0 * x * y) + cy;
|
||||
x = xx;
|
||||
if (((x * x) + (y * y)) > 100.0) iteration = 999999;
|
||||
}
|
||||
val = (((x * x) + (y * y)) * 2.55) / 100.0;
|
||||
if (val > 255) val = 255;
|
||||
if (iteration >= 99999)
|
||||
{
|
||||
rr = (r * val) / 255;
|
||||
gg = (g * val) / 255;
|
||||
bb = (b * val) / 255;
|
||||
pix[(hy * w) + hx] =
|
||||
(val << 24) | (rr << 16) | (gg << 8) | (bb);
|
||||
}
|
||||
else
|
||||
pix[(hy * w) + hx] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
th_do(void *data, Ecore_Thread *th)
|
||||
{
|
||||
struct info *inf = data;
|
||||
// CANNOT TOUCH inf->obj here! just inf->pix which is 256x256 @ 32bpp
|
||||
// quick and dirty to consume some cpu - do a mandelbrot calc
|
||||
mandel(inf->pix, 256, 256);
|
||||
}
|
||||
//
|
||||
// END - code running in my custom pthread instance
|
||||
|
||||
static void // thread job finished - collect results and put in img obj
|
||||
th_end(void *data, Ecore_Thread *th)
|
||||
{
|
||||
struct info *inf = data;
|
||||
|
||||
// copy data to object, free calculated data and info struc
|
||||
evas_object_image_data_copy_set(inf->obj, inf->pix);
|
||||
evas_object_show(inf->obj);
|
||||
free(inf->pix);
|
||||
free(inf);
|
||||
}
|
||||
|
||||
static void // if the thread is cancelled - free pix, keep obj tho
|
||||
th_cancel(void *data, Ecore_Thread *th)
|
||||
{
|
||||
struct info *inf = data;
|
||||
|
||||
// just free pixel data and info struct
|
||||
free(inf->pix);
|
||||
free(inf);
|
||||
}
|
||||
|
||||
static Eina_Bool // animate the objects so you see all the madels move
|
||||
anim(void *data)
|
||||
{
|
||||
Evas_Object *o = data;
|
||||
double t, z;
|
||||
int w, h, v;
|
||||
Evas_Coord x, y;
|
||||
|
||||
// just calculate some position using the pointer value of the object as
|
||||
// a seed value to make different objects go into different places over time
|
||||
v = ((int)o) & 0xff;
|
||||
t = ecore_loop_time_get();
|
||||
w = 100 + ((v * 100) >> 8);
|
||||
h = 100 + ((v * 100) >> 8);
|
||||
z = (double)(v) / 100.0;
|
||||
x = (w * sin(t));
|
||||
y = (h * cos(t + z));
|
||||
// do the actual move
|
||||
evas_object_move(o, 200 + x - 128, 200 + y - 128);
|
||||
// keep looping - return true
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
elm_main(int argc, char **argv)
|
||||
{
|
||||
Evas_Object *o, *bg;
|
||||
int i;
|
||||
|
||||
win = elm_win_add(NULL, "efl-thread-1", ELM_WIN_BASIC);
|
||||
elm_win_title_set(win, "EFL Thread 1");
|
||||
evas_object_resize(win, 400, 400);
|
||||
evas_object_show(win);
|
||||
|
||||
bg = elm_bg_add(win);
|
||||
elm_win_resize_object_add(win, bg);
|
||||
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||
evas_object_show(bg);
|
||||
|
||||
// queue up 64 mandel generation thread jobs
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
struct info *inf;
|
||||
|
||||
// create ecore thread to do some threaded job inside the worker pool
|
||||
inf = malloc(sizeof(struct info));
|
||||
if (inf)
|
||||
{
|
||||
Evas_Object *o;
|
||||
|
||||
o = evas_object_image_filled_add(evas_object_evas_get(win));
|
||||
evas_object_image_size_set(o, 256, 256);
|
||||
evas_object_image_alpha_set(o, EINA_TRUE);
|
||||
evas_object_resize(o, 256, 256);
|
||||
inf->obj = o;
|
||||
inf->pix = malloc(256 * 256 * sizeof(int));
|
||||
ecore_thread_run(th_do, th_end, th_cancel, inf);
|
||||
// bonus - slide the objects around all the time with an
|
||||
// animator that ticks off every frame.
|
||||
ecore_animator_add(anim, o);
|
||||
}
|
||||
}
|
||||
|
||||
elm_run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ELM_MAIN()
|
||||
|
Loading…
Reference in New Issue