forked from enlightenment/efl
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 progressbar_example
|
||||||
*
|
*
|
||||||
* @ref slideshow_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
|
* @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
|
* @page bg_example_01_c bg_example_01.c
|
||||||
* @include bg_example_01.c
|
* @include bg_example_01.c
|
||||||
|
@ -6087,3 +6218,39 @@
|
||||||
* @include slideshow_example.c
|
* @include slideshow_example.c
|
||||||
* @example 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 widgetslist - These are the widgets you'll compose your UI out of.
|
||||||
* @li @ref containerslist - These are the containers in which the widgets will
|
* @li @ref containerslist - These are the containers in which the widgets will
|
||||||
* be laid out.
|
* be laid out.
|
||||||
|
*
|
||||||
|
* Also see other generic EFL programming guides:
|
||||||
|
* @li @ref threading
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @page widgetslist Widget list
|
* @page widgetslist Widget list
|
||||||
|
@ -290,3 +293,23 @@
|
||||||
* @li @ref infralist - These are modules that deal with Elementary as a whole.
|
* @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.
|
* @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 \
|
table_example_02.c \
|
||||||
menu_example_01.c \
|
menu_example_01.c \
|
||||||
thumb_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 =
|
pkglib_PROGRAMS =
|
||||||
|
|
||||||
|
@ -217,7 +223,13 @@ pkglib_PROGRAMS += \
|
||||||
table_example_02 \
|
table_example_02 \
|
||||||
menu_example_01 \
|
menu_example_01 \
|
||||||
thumb_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
|
# This variable will hold the list of screenshots that will be made
|
||||||
# by "make screenshots". Each item in the list is of the form:
|
# 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