Tizen Native API
|
Functions | |
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. | |
Ecore_Thread * | ecore_thread_feedback_run (Ecore_Thread_Cb func_heavy, Ecore_Thread_Notify_Cb func_notify, Ecore_Thread_Cb func_end, Ecore_Thread_Cb func_cancel, const void *data, Eina_Bool try_no_queue) |
Launches a thread to run a task that can talk back to the main thread. | |
Eina_Bool | ecore_thread_cancel (Ecore_Thread *thread) |
Cancels a running thread. | |
Eina_Bool | ecore_thread_check (Ecore_Thread *thread) |
Checks whether a thread is in pending cancellation. | |
Eina_Bool | ecore_thread_feedback (Ecore_Thread *thread, const void *msg_data) |
Sends data from the worker thread to the main loop. | |
Eina_Bool | ecore_thread_reschedule (Ecore_Thread *thread) |
Asks for the function in the thread to be called again at a later period. | |
int | ecore_thread_active_get (void) |
Gets the number of active threads running jobs. | |
int | ecore_thread_pending_get (void) |
Gets the number of short jobs waiting for a thread to run. | |
int | ecore_thread_pending_feedback_get (void) |
Gets the number of feedback jobs waiting for a thread to run. | |
int | ecore_thread_pending_total_get (void) |
Gets the total number of pending jobs. | |
int | ecore_thread_max_get (void) |
Gets the maximum number of threads that can run simultaneously. | |
void | ecore_thread_max_set (int num) |
Sets the maximum number of threads allowed to run simultaneously. | |
void | ecore_thread_max_reset (void) |
Resets the maximum number of concurrently running threads to the default. | |
int | ecore_thread_available_get (void) |
Gets the number of threads available for running tasks. | |
Eina_Bool | ecore_thread_local_data_add (Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct) |
Adds some data present in the hash local to the thread. | |
void * | ecore_thread_local_data_set (Ecore_Thread *thread, const char *key, void *value, Eina_Free_Cb cb) |
Sets some data present in the hash local to the given thread. | |
void * | ecore_thread_local_data_find (Ecore_Thread *thread, const char *key) |
Gets data stored in the hash local to the given thread. | |
Eina_Bool | ecore_thread_local_data_del (Ecore_Thread *thread, const char *key) |
Deletes the data corresponding to the given key from the thread's hash. | |
Eina_Bool | ecore_thread_global_data_add (const char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct) |
Adds some data to a hash shared by all threads. | |
void * | ecore_thread_global_data_set (const char *key, void *value, Eina_Free_Cb cb) |
Sets some data in the hash shared by all threads. | |
void * | ecore_thread_global_data_find (const char *key) |
Gets data stored in the hash shared by all threads. | |
Eina_Bool | ecore_thread_global_data_del (const char *key) |
Deletes the data corresponding to the given key from the shared hash. | |
void * | ecore_thread_global_data_wait (const char *key, double seconds) |
Gets data stored in the shared hash or waits for it if it doesn't exist. | |
Typedefs | |
typedef struct _Ecore_Thread | Ecore_Thread |
A handle for threaded jobs. | |
typedef void(* | Ecore_Thread_Cb )(void *data, Ecore_Thread *thread) |
Called to be used by Ecore_Thread helper. | |
typedef void(* | Ecore_Thread_Notify_Cb )(void *data, Ecore_Thread *thread, void *msg_data) |
Called to be used by the main loop to receive data sent by an Ecore Thread. |
Facilities to run heavy tasks in different threads to avoid blocking the main loop.
The EFL is, for the most part, not thread safe. This means that if you have some task running in another thread and you have, for example, an Evas object to show the status progress of this task, you cannot update the object from within the thread. This can only be done from the main thread, the one running the main loop. This problem can be solved by running a thread that sends messages to the main one using an Ecore_Pipe, but when you need to handle other things like cancelling the thread, your code grows in complexity and gets much harder to maintain.
Ecore Thread is here to solve that problem. It is not a simple wrapper around standard POSIX threads (or an equivalent in other systems) and it's not meant to be used to run parallel tasks throughout the entire duration of the program, especially when these tasks are performance critical, as Ecore manages these tasks using a pool of threads based on system configuration.
What Ecore Thread does is it makes it a lot easier to dispatch a worker function to perform some heavy tasks and then get the result once it completes, without blocking the application's UI. In addition, cancelling and rescheduling comes practically for free and the developer need not worry about how many threads are launched, since Ecore schedules them according to the number of processors the system has and the maximum amount of concurrent threads set for the application.
At the system level, Ecore starts a new thread on an as-needed basis until the maximum set is reached. When no more threads can be launched, new worker functions are queued in a waiting list until a thread becomes available. This way, system threads are shared throughout different worker functions, but running only one at a time. At the same time, a worker function that is rescheduled may be run on a different thread the next time.
The Ecore_Thread handler has two meanings, depending on what context it is on. The one returned when starting a worker with any of the functions ecore_thread_run() or ecore_thread_feedback_run() is an identifier of that specific instance of the function and can be used from the main loop with the ecore_thread_cancel() and ecore_thread_check() functions. This handler must not be shared with the worker function running in the thread. This same handler is the one received on the end
, cancel
, and feedback
callbacks.
The worker function, that's the one running in the thread, also receives an Ecore_Thread handler that can be used with ecore_thread_cancel() and ecore_thread_check(), sharing the flag with the main loop. But this handler is also associated with the thread where the function is running. This has strong implications when working with thread local data.
There are two kinds of worker threads that Ecore handles: simple or short, workers, and feedback workers.
The first kind is for simple functions that perform a usually small but time consuming task. Ecore runs this function in a thread as soon as one becomes available and notifies the calling user of its completion once the task is done.
The following image shows the flow of a program running four tasks on a pool of two threads.
For larger tasks that may require continuous communication with the main program, the feedback workers provide the same functionality plus a way for the function running in the thread to send messages to the main thread.
The next diagram omits some details shown in the previous one regarding how threads are spawned and tasks are queued, but illustrates how feedback jobs communicate with the main loop and the special case of threads running out of the pool.
int ecore_thread_active_get | ( | void | ) |
Gets the number of active threads running jobs.
This returns the number of threads currently running jobs of any type through the Ecore_Thread API.
int ecore_thread_available_get | ( | void | ) |
Gets the number of threads available for running tasks.
Eina_Bool ecore_thread_cancel | ( | Ecore_Thread * | thread | ) |
Cancels a running thread.
This function cancels a running thread. If thread can be immediately cancelled (its still pending execution after creation or rescheduling), then the cancel callback is called, thread is freed and the function returns EINA_TRUE.
EINA_FALSE
after marking the thread as pending cancellation. For the thread to actually be terminated, it needs to return from the user function back into Ecore control. This can happen in several ways: [in] | thread | The thread to cancel |
EINA_FALSE
if it is pendingEina_Bool ecore_thread_check | ( | Ecore_Thread * | thread | ) |
Checks whether a thread is in pending cancellation.
This function can be called both in the main loop and in the running thread.
[in] | thread | The thread to test |
EINA_FALSE
if it is notEina_Bool ecore_thread_feedback | ( | Ecore_Thread * | thread, |
const void * | msg_data | ||
) |
Sends data from the worker thread to the main loop.
[in] | thread | The current Ecore_Thread context to send data from |
[in] | msg_data | The data to be transmitted to the main loop |
EINA_FALSE
if anything goes wrongEcore_Thread* ecore_thread_feedback_run | ( | Ecore_Thread_Cb | func_heavy, |
Ecore_Thread_Notify_Cb | func_notify, | ||
Ecore_Thread_Cb | func_end, | ||
Ecore_Thread_Cb | func_cancel, | ||
const void * | data, | ||
Eina_Bool | try_no_queue | ||
) |
Launches a thread to run a task that can talk back to the main thread.
[in] | func_heavy | The function that should run in another thread |
[in] | func_notify | the function that receives the data sent from the thread |
[in] | func_end | The function to call from the main loop when func_heavy completes its task successfully |
[in] | func_cancel | The function to call from the main loop if the thread running func_heavy is cancelled or fails to start |
[in] | data | The user context data to pass to all callbacks |
[in] | try_no_queue | The boolean value that indicates whether to run outside the thread pool |
NULL
on failureEina_Bool ecore_thread_global_data_add | ( | const char * | key, |
void * | value, | ||
Eina_Free_Cb | cb, | ||
Eina_Bool | direct | ||
) |
Adds some data to a hash shared by all threads.
Neither key nor value may be NULL
and key gets copied in the hash, unless direct is set, in which case the string used should not be freed until the data is removed from the hash.
NULL
, in which case value needs to be manually freed after removing it from the hash with either by ecore_thread_global_data_del() or ecore_thread_global_data_set().Manually freeing any data that is added to the hash with the cb function is likely to produce a segmentation fault, or any other strange happening at a later stage in the program.
[in] | key | The name under which the data is stored |
[in] | value | The data to add |
[in] | cb | The function to free the data when removed from the hash |
[in] | direct | If true , this does not copy the key string (like eina_hash_direct_add()), otherwise false |
EINA_FALSE
on failureEina_Bool ecore_thread_global_data_del | ( | const char * | key | ) |
Deletes the data corresponding to the given key from the shared hash.
key
that is stored in the global hash, this function removes it from the hash and returns EINA_TRUE. If no data exists or an error occurs, it returns EINA_FALSE
.Note, also, that freeing data that other threads may be using results in a crash, so appropriate care must be taken by the application when that possibility exists.
[in] | key | The name under which the data is stored |
EINA_FALSE
on failurevoid* ecore_thread_global_data_find | ( | const char * | key | ) |
Gets data stored in the hash shared by all threads.
This finds and returns the data stored in the shared hash under the key key.
[in] | key | The name under which the data is stored |
NULL
on an errorvoid* ecore_thread_global_data_set | ( | const char * | key, |
void * | value, | ||
Eina_Free_Cb | cb | ||
) |
Sets some data in the hash shared by all threads.
NULL
. The key itself is copied.If the hash already contains something under key, the data is replaced by value and the old value is returned.
NULL
is also returned if either key or value is NULL
, or if an error occurs.
[in] | key | The name under which the data is stored |
[in] | value | The data to add |
[in] | cb | The function to free the data when removed from the hash |
void* ecore_thread_global_data_wait | ( | const char * | key, |
double | seconds | ||
) |
Gets data stored in the shared hash or waits for it if it doesn't exist.
If there's nothing in the hash under the given key, the function blocks and waits for seconds seconds for some other thread to add it with either ecore_thread_global_data_add() or ecore_thread_global_data_set(). If after waiting there's still no data to obtain, NULL
is returned.
If seconds is 0
, then no waiting happens and this function works like ecore_thread_global_data_find(). If seconds is less than 0
, then the function waits indefinitely.
[in] | key | The name under which the data is stored |
[in] | seconds | The amount of time in seconds to wait for the data |
NULL
on an errorEina_Bool ecore_thread_local_data_add | ( | Ecore_Thread * | thread, |
const char * | key, | ||
void * | value, | ||
Eina_Free_Cb | cb, | ||
Eina_Bool | direct | ||
) |
Adds some data present in the hash local to the thread.
@ This set of functions is useful to share things around several instances of a function when that thing is costly to create and can be reused, but may only be used by one function at a time.
For example, if you have a program doing requisitions to a database, these requisitions can be done in threads so that waiting for the database to respond doesn't block the UI. Each of these threads run a function, and each function is dependent on a connection to the database, which may not be able to handle more than one request at a time so for each running function you need one connection handle.
The options then are:
The last option is the most efficient, but it requires a lot of work to be implemented properly. Using thread local data helps to achieve the same result while avoiding all the tracking work on your code. The way to use it would be at the worker function, to ask for the connection using ecore_thread_local_data_find() and if it doesn't exist, then open a new one and save it with ecore_thread_local_data_add(). Complete the work and forget about the connection handle, when everything is done the function just ends. The next worker to run on that thread checks if a connection exists and finds that it does, so the process of opening a new one has been spared. When no more workers exist, the thread is destroyed and the callback used when saving the connection is called to close it.
Neither key nor value may be NULL
and key gets copied in the hash, unless direct is set, in which case the string used should not be freed until the data is removed from the hash.
NULL
, in which case value needs to be manually freed after removing it from the hash with either ecore_thread_local_data_del() or ecore_thread_local_data_set(), but it's very unlikely that this is what you want.This function, and all of the others in the ecore_thread_local_data family of functions, can only be called within the worker function running in the thread. Do not call them from the main loop or from a thread other than the one represented by thread.
[in] | thread | The thread context the data belongs to |
[in] | key | The name under which the data is stored |
[in] | value | The data to add |
[in] | cb | The function to free the data when removed from the hash |
[in] | direct | If true , this does not copy the key string (like eina_hash_direct_add()), otherwise false |
EINA_FALSE
on failureEina_Bool ecore_thread_local_data_del | ( | Ecore_Thread * | thread, |
const char * | key | ||
) |
Deletes the data corresponding to the given key from the thread's hash.
EINA_FALSE
.[in] | thread | The thread context the data belongs to |
[in] | key | The name under which the data is stored |
EINA_FALSE
on failurevoid* ecore_thread_local_data_find | ( | Ecore_Thread * | thread, |
const char * | key | ||
) |
Gets data stored in the hash local to the given thread.
This finds and returns the data stored in the shared hash under the key key.
[in] | thread | The thread context the data belongs to |
[in] | key | The name under which the data is stored |
NULL
on an errorvoid* ecore_thread_local_data_set | ( | Ecore_Thread * | thread, |
const char * | key, | ||
void * | value, | ||
Eina_Free_Cb | cb | ||
) |
Sets some data present in the hash local to the given thread.
NULL
. The key itself is copied.If the hash already contains something under key, the data is replaced by value and the old value is returned.
NULL
is also returned if either key or value are NULL
, or if an error occurs.
[in] | thread | The thread context the data belongs to |
[in] | key | The name under which the data is stored |
[in] | value | The data to add |
[in] | cb | The function to free the data when removed from the hash |
int ecore_thread_max_get | ( | void | ) |
Gets the maximum number of threads that can run simultaneously.
This returns the maximum number of Ecore_Thread's that may be running at the same time. If this number is reached, new jobs started by either ecore_thread_run() or ecore_thread_feedback_run() are added to the respective pending queues until one of the running threads finishes its task and becomes available to run a new one.
1
if this value could not be fetched.void ecore_thread_max_reset | ( | void | ) |
Resets the maximum number of concurrently running threads to the default.
This resets the value returned by ecore_thread_max_get() back to its default.
void ecore_thread_max_set | ( | int | num | ) |
Sets the maximum number of threads allowed to run simultaneously.
This sets a new value for the maximum number of concurrently running Ecore_Thread's. It must be an integer between 1
and (16
* x
), where x
is the number for CPUs available.
[in] | num | The new maximum |
int ecore_thread_pending_feedback_get | ( | void | ) |
Gets the number of feedback jobs waiting for a thread to run.
This returns the number of tasks started with ecore_thread_feedback_run() that are pending and waiting for a thread to become available to run them.
int ecore_thread_pending_get | ( | void | ) |
Gets the number of short jobs waiting for a thread to run.
This returns the number of tasks started with ecore_thread_run() that are pending and waiting for a thread to become available to run them.
int ecore_thread_pending_total_get | ( | void | ) |
Gets the total number of pending jobs.
Eina_Bool ecore_thread_reschedule | ( | Ecore_Thread * | thread | ) |
Asks for the function in the thread to be called again at a later period.
Calling this function marks the thread for a reschedule, so as soon as it returns, it is added to the end of the list of pending tasks. If no other tasks are waiting or there are sufficient threads available, the rescheduled task is launched again immediately.
This should never return EINA_FALSE
, unless it is called from the wrong thread or with the wrong arguments.
[in] | thread | The current Ecore_Thread context to reschedule |
EINA_FALSE
if anything goes wrong 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.
This function tries to create a new thread to run func_blocking in, or if the maximum number of concurrent threads has been reached it adds it to the pending list, where it waits until a thread becomes available. The return value is an Ecore_Thread handle that can be used to cancel the thread before its completion.
thread
parameter is NULL
. It's also safe to call any EFL function here, as it is running in the main thread.[in] | func_blocking | The function that should run in another thread |
[in] | func_end | The function to call from the main loop when func_blocking completes its task successfully (may be NULL ) |
[in] | func_cancel | The function to call from the main loop if the thread running func_blocking is cancelled or fails to start (may be NULL ) |
[in] | data | The user context data to pass to all callbacks |
NULL
on failure