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".

//Compile with:
//gcc -o efl_thread_6 efl_thread_6.c -g `pkg-config --cflags --libs elementary`
#include <Elementary.h>
static Evas_Object *win = NULL;
static Eina_List *threads;
struct info
{
int *pix;
};
// BEGIN - code running in my custom thread instance
//
static void
mandel(Ecore_Thread *th, 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++)
{
// every line check if thread has been cancelled to return early
if (ecore_thread_check(th)) return;
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(th, inf->pix, 256, 256);
}
//
// END - code running in my custom thread 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);
threads = eina_list_remove(threads, th);
}
static void // if the thread is cancelled - free pix, keep obj tho
th_cancel(void *data, Ecore_Thread *th EINA_UNUSED)
{
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)(uintptr_t)o) & 0xff;
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;
}
EAPI_MAIN int
elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{
int i;
win = elm_win_util_standard_add("efl-thread-6", "EFL Thread 6");
// 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_resize(o, 256, 256);
inf->obj = o;
inf->pix = malloc(256 * 256 * sizeof(int));
th = ecore_thread_run(th_do, th_end, th_cancel, inf);
threads = eina_list_append(threads, th);
// bonus - slide the objects around all the time with an
// animator that ticks off every frame.
}
}
evas_object_resize(win, 400, 400);
// if some threads are still running - cancel them
return 0;
}
int Evas_Coord
Type used for coordinates (in pixels, int).
Definition: Evas_Common.h:116
Ecore_Animator * ecore_animator_add(Ecore_Task_Cb func, const void *data)
Adds an animator to call func at every animation tick during main loop execution.
Definition: ecore_anim.c:537
struct _Ecore_Thread Ecore_Thread
A handle for threaded jobs.
Definition: Ecore_Common.h:1729
Ecore_Thread * ecore_thread_run(Ecore_Thread_Cb func_blocking, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data)
Schedules a task to run in a parallel thread to avoid locking the main loop.
Definition: ecore_thread.c:658
Eina_Bool ecore_thread_check(Ecore_Thread *thread)
Checks if a thread is pending cancellation.
Definition: ecore_thread.c:892
Eina_Bool ecore_thread_cancel(Ecore_Thread *thread)
Cancels a running thread.
Definition: ecore_thread.c:741
double ecore_loop_time_get(void)
Retrieves the time at which the last loop stopped waiting for timeouts or events.
Definition: ecore_time.c:74
EINA_API Eina_List * eina_list_append(Eina_List *list, const void *data)
Appends the given data to the given linked list.
Definition: eina_list.c:584
EINA_API Eina_List * eina_list_remove(Eina_List *list, const void *data)
Removes the first instance of the specified data from the given list.
Definition: eina_list.c:773
#define EINA_LIST_FREE(list, data)
Definition for the macro to remove each list node while having access to each node's data.
Definition: eina_list.h:1629
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
#define ELM_MAIN()
macro to be used after the elm_main() function
Definition: elm_general.h:556
Eina_Bool elm_policy_set(unsigned int policy, int value)
Set a new policy's value (for a given policy group/identifier).
Definition: elm_main.c:1380
void elm_run(void)
Run Elementary's main loop.
Definition: elm_main.c:1357
@ ELM_POLICY_QUIT_LAST_WINDOW_CLOSED
quit when the application's last window is closed
Definition: elm_general.h:248
@ ELM_POLICY_QUIT
under which circumstances the application should quit automatically.
Definition: elm_general.h:227
Evas_Object * elm_win_util_standard_add(const char *name, const char *title)
Adds a window object with standard setup.
Definition: efl_ui_win.c:9582
void elm_win_autodel_set(Eo *obj, Eina_Bool autodel)
Set the window's autodel state.
Definition: efl_ui_win.c:6194
EVAS_API void evas_object_image_data_copy_set(Eo *eo_obj, void *data)
Replaces the raw image data of the given image object.
Definition: evas_image_legacy.c:799
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
EVAS_API void evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
Move the given Evas object to the given location inside its canvas' viewport.
Definition: evas_object_main.c:1171
EVAS_API Evas * evas_object_evas_get(const Eo *eo_obj)
Get the Evas to which this object belongs to.
Definition: evas_object_main.c:2662
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185
EVAS_API void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
Changes the size of the given Evas object.
Definition: evas_object_main.c:1236
EVAS_API void evas_object_image_size_set(Evas_Object *eo_obj, int w, int h)
Sets the size of the given image object.
Definition: evas_image_legacy.c:847
EVAS_API void evas_object_image_alpha_set(Evas_Object *obj, Eina_Bool alpha)
Enable or disable alpha channel usage on the given image object.
Definition: evas_image_legacy.c:103
EVAS_API Evas_Object * evas_object_image_filled_add(Evas *eo_e)
Creates a new image object that automatically scales its bound image to the object's area,...
Definition: evas_image_legacy.c:35
Type for a generic double linked list.
Definition: eina_list.h:318