Asynchronous Queues

Asynchronous Queues — Асинхронное взаимодействие между потоками.

Краткое описание

#include <glib.h> GAsyncQueue; GAsyncQueue* g_async_queue_new (void); GAsyncQueue* g_async_queue_ref (GAsyncQueue *queue); void g_async_queue_unref (GAsyncQueue *queue); void g_async_queue_push (GAsyncQueue *queue, gpointer data); void g_async_queue_push_sorted (GAsyncQueue *queue, gpointer data, GCompareDataFunc func, gpointer user_data); gpointer g_async_queue_pop (GAsyncQueue *queue); gpointer g_async_queue_try_pop (GAsyncQueue *queue); gpointer g_async_queue_timed_pop (GAsyncQueue *queue, GTimeVal *end_time); gint g_async_queue_length (GAsyncQueue *queue); void g_async_queue_sort (GAsyncQueue *queue, GCompareDataFunc func, gpointer user_data); void g_async_queue_lock (GAsyncQueue *queue); void g_async_queue_unlock (GAsyncQueue *queue); void g_async_queue_ref_unlocked (GAsyncQueue *queue); void g_async_queue_unref_and_unlock (GAsyncQueue *queue); void g_async_queue_push_unlocked (GAsyncQueue *queue, gpointer data); void g_async_queue_push_sorted_unlocked (GAsyncQueue *queue, gpointer data, GCompareDataFunc func, gpointer user_data); gpointer g_async_queue_pop_unlocked (GAsyncQueue *queue); gpointer g_async_queue_try_pop_unlocked (GAsyncQueue *queue); gpointer g_async_queue_timed_pop_unlocked (GAsyncQueue *queue, GTimeVal *end_time); gint g_async_queue_length_unlocked (GAsyncQueue *queue); void g_async_queue_sort_unlocked (GAsyncQueue *queue, GCompareDataFunc func, gpointer user_data);

Описание

Часто вам нужна взаимосвязь между разными потоками. В общем более безопасно делать это не с помощью общей памяти, а явно передавать сообщения. Эти сообщения имеют смысл только если они асинхронны для много-поточных приложений, однако, синхронные операции могут также выполняться в тех же потоках.

Асинхронные структуры данных являются исключением из большинства других структур данных GLib, поскольку они могут использоваться одновременно в множестве потоков без явной блокировки и они имеют свой собственный встроенный подсчет ссылок. Так как асинхронные структуры данных будут всегда использоваться как минимум двумя параллельными потоками.

Для использования асинхронной структуры сначала нужно её создать с помощью g_async_queue_new(). Вновь созданная структура имеет количество ссылок равное 1. Каждый раз, когда другой поток создаёт новую ссылку на (то есть указатель на) структуру, количество её ссылок увеличивается (используется g_async_queue_ref()). Также, перед удаление этой ссылки, количество ссылок уменьшается (используется g_async_queue_unref()). После этого структура не может больше существовать, поэтому вы не должны обращаться к ней.

Поток который хочет отправить сообщение в эту структуру просто вызывает g_async_queue_push() для помещения сообщения в очередь.

Поток который ожидает сообщение из асинхронной структуры просто вызывает g_async_queue_pop() для этой очереди. Если нет доступных сообщений в указанной очереди, поток засыпает пока не появится сообщение. Сообщение удаляется из очереди и возвращается. Функции g_async_queue_try_pop() и g_async_queue_timed_pop() могут использоваться только для проверки присутствия сообщений или ожидания определенное время сообщений соответственно.

Почти для каждой функции существует два варианта, первый блокирует очередь, а второй не делает этого. Таким образом вы можете удерживать блокировку очереди (блокировать с помощью href="glib-Asynchronous-Queues.html#g-async-queue-lock">g_async_queue_lock() и освобождать с помощью g_async_queue_unlock()) через множественные инструкции доступа к очереди. Это может быть необходимо для гарантирования целостности очереди, но должно использоваться только когда это действительно необходимо, так как может усложнить вам жизнь при неблагоразумном использовании. Обычно вы должны использовать только варианты функции блокировки (то есть без суффикса _unlocked)

Детали

GAsyncQueue

typedef struct _GAsyncQueue GAsyncQueue;

Структура GAsyncQueue - это закрытая структура данных, которые представляют асинхронную очередь. Доступ к этим данным должен осуществляться только с помощью функций g_async_queue_*.


g_async_queue_new ()

GAsyncQueue* g_async_queue_new (void);

Создаёт новую асинхронную структуру с начальным количеством ссылок равным 1.

Возвращает : новая GAsyncQueue.

g_async_queue_ref ()

GAsyncQueue* g_async_queue_ref (GAsyncQueue *queue);

Увеличивает количество ссылок асинхронной queue на 1. Вы не должны удерживать блокировку для вызова этой функции.

queue : GAsyncQueue.
Возвращает : queue которую помещали (Начиная с версии 2.6)

g_async_queue_unref ()

void g_async_queue_unref (GAsyncQueue *queue);

Уменьшает количество ссылок асинхронной queue на 1. Если количество ссылок дошло до 0, queue уничтожается и память распределённая для неё освобождается. Таким образом вам нельзя использовать queue впоследствии. Вам не нужно удерживать блокировку для вызова этой функции.

queue : GAsyncQueue.

g_async_queue_push ()

void g_async_queue_push (GAsyncQueue *queue, gpointer data);

Помещает data в queue. data должен быть не NULL.

queue : GAsyncQueue.
data : data помещаемые в queue.

g_async_queue_push_sorted ()

void g_async_queue_push_sorted (GAsyncQueue *queue, gpointer data, GCompareDataFunc func, gpointer user_data);

Вставляет data в queue используя func для определения новой позиции.

Перед использованием функции для вставки нового элемента, queue должна быть отсортирована.

Эта функция блокирует queue перед сортировкой и разблокирует после завершения работы.

Для примера func смотрите g_async_queue_sort().

queue : GAsyncQueue
data : data помещаемые в queue
func : GCompareDataFunc используемая для сортировки queue. Помещая в эту функцию два элемента queue, функция возвращает 0 если они эквивалентны, отрицательное если первый элемент должен быть выше в queue или положительное значение, если первый элемент должен быть ниже в queue чем второй элемент.
user_data : пользовательские данные помещаемые в func.

Начиная с версии 2.10


g_async_queue_pop ()

gpointer g_async_queue_pop (GAsyncQueue *queue);

Выталкивает данные из queue. Эта функция блокируется пока данные доступны.

queue : GAsyncQueue.
Возвращает : данные из очереди.

g_async_queue_try_pop ()

gpointer g_async_queue_try_pop (GAsyncQueue *queue);

Пытается вытолкнуть данные из очереди queue. Если данные не доступны, возвращает NULL.

queue : GAsyncQueue.
Возвращает : данные из очереди или NULL, если нет немедленно доступных данных.

g_async_queue_timed_pop ()

gpointer g_async_queue_timed_pop (GAsyncQueue *queue, GTimeVal *end_time);

Выталкивает данные из очереди queue. Если данные получены перед end_time, возвращает NULL.

Для простоты расчёта параметра end_time можно использовать комбинацию g_get_current_time() и g_time_val_add().

queue : GAsyncQueue.
end_time : GTimeVal, определяющая время завершения.
Возвращает : данные из очереди или NULL, если данные получены раньше end_time.

g_async_queue_length ()

gint g_async_queue_length (GAsyncQueue *queue);

Возвращает длину очереди, отрицательное значение означает ожидание потоков, положительное значение означает доступность ввода в queue. Фактически эта функция возвращает количество элементов данных в очереди минус количество ожидающих потоков. Таким образом возвращаемое значение 0 может означать 'n' входов в очередь и 'n' потоков ожидания. Это может произойти или из-за блокировки очереди или из-за планирования.

queue : GAsyncQueue.
Возвращает : длина queue.

g_async_queue_sort ()

void g_async_queue_sort (GAsyncQueue *queue, GCompareDataFunc func, gpointer user_data);

Сортирует queue используя func.

Эта функция блокирует queue перед сортировкой и разблокирует после завершения.

Если вам нужно отсортировать список по приоритету, чтобы убедиться что низший приоритет будет сверху очереди, вы должны использовать:

gint32 id1; gint32 id2; id1 = GPOINTER_TO_INT (element1); id2 = GPOINTER_TO_INT (element2); return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);

queue : GAsyncQueue
func : GCompareDataFunc используемая для сортировки queue. Помещая в эту функцию два элемента queue, функция возвращает 0 если они эквивалентны, отрицательное если первый элемент должен быть выше в queue или положительное значение, если первый элемент должен быть ниже в queue чем второй элемент.
user_data : пользовательские данные помещаемые в func

Начиная с версии 2.10


g_async_queue_lock ()

void g_async_queue_lock (GAsyncQueue *queue);

Блокирует queue's. После этого вы можете вызвать только g_async_queue_*_unlocked() вариант функции для этой queue. Иначе она зависнет (deadlock).

queue : GAsyncQueue.

g_async_queue_unlock ()

void g_async_queue_unlock (GAsyncQueue *queue);

Снимает блокировку queue's.

queue : GAsyncQueue.

g_async_queue_ref_unlocked ()

void g_async_queue_ref_unlocked (GAsyncQueue *queue);

Внимание

g_async_queue_ref_unlocked устарела и не должна использоваться во вновь создаваемом коде.

Увеличивает количество ссылок асинхронной queue на 1.

Устарела: Начиная с версии 2.8, подсчёт ссылок сделан атомарным, поэтому g_async_queue_ref() может использоваться независимо от блокировки queue's.

queue : GAsyncQueue.

g_async_queue_unref_and_unlock ()

void g_async_queue_unref_and_unlock (GAsyncQueue *queue);

Внимание

g_async_queue_unref_and_unlock устарела и не должна использоваться во вновь создаваемом коде.

Уменьшает количество ссылок асинхронной queue на 1 и отменяет блокировку. Эта функция должна вызываться во время удержания блокировки queue's. Если количество ссылок достигло 0, queue будет уничтожена и память распределённая для неё будет освобождена.

Устарела: Начиная с версии 2.8, подсчёт ссылок выполняется атомарно, поэтому g_async_queue_unref() может использоваться независимо от блокировки queue's.

queue : GAsyncQueue.

g_async_queue_push_unlocked ()

void g_async_queue_push_unlocked (GAsyncQueue *queue, gpointer data);

Помещает data в queue. data должен быть не NULL. Эта функция должна вызываться в течении блокировки queue's.

queue : GAsyncQueue.
data : данные для помещения в queue.

g_async_queue_push_sorted_unlocked ()

void g_async_queue_push_sorted_unlocked (GAsyncQueue *queue, gpointer data, GCompareDataFunc func, gpointer user_data);

Вставляет data в queue используя func для определения новой позиции.

Перед использованием этой функции для вставки нового элемента queue должна быть отсортирована.

Эта функция вызывается в течении блокировки queue's.

В качестве примера func смотрите g_async_queue_sort().

queue : GAsyncQueue
data : данные для помещения в queue
func : GCompareDataFunc используемая для сортировки queue. Помещая в эту функцию два элемента queue, функция возвращает 0 если они эквивалентны, отрицательное если первый элемент должен быть выше в queue или положительное значение, если первый элемент должен быть ниже в queue чем второй элемент.
user_data : пользовательские данные помещаемые в func.

Начиная с версии 2.10


g_async_queue_pop_unlocked ()

gpointer g_async_queue_pop_unlocked (GAsyncQueue *queue);

Выталкивает данные из queue. Функция блокируется пока данные доступны. Должна вызываться во время блокировки queue's.

queue : GAsyncQueue.
Возвращает : данные из очереди.

g_async_queue_try_pop_unlocked ()

gpointer g_async_queue_try_pop_unlocked (GAsyncQueue *queue);

Пытается вытолкнуть данные из queue. Если данные не доступны, возвращается NULL. Функция должна вызываться во время блокировки queue's.

queue : GAsyncQueue.
Возвращает : данные из очереди или NULL, если нет немедленно доступных данных.

g_async_queue_timed_pop_unlocked ()

gpointer g_async_queue_timed_pop_unlocked (GAsyncQueue *queue, GTimeVal *end_time);

Выталкивает данные из queue. Если данные получены раньше end_time, возвращает NULL. Эта функция должна вызываться во время блокировки queue's.

Для простоты расчета end_time можно использовать комбинацию g_get_current_time() и g_time_val_add().

queue : GAsyncQueue.
end_time : GTimeVal, определяющая время завершения.
Возвращает : данные из очереди или NULL, если нет данных полученных раньше end_time.

g_async_queue_length_unlocked ()

gint g_async_queue_length_unlocked (GAsyncQueue *queue);

Возвращает длину очереди, отрицательное значение означает ожидание потоков, положительное значение означает доступность ввода в queue. Фактически эта функция возвращает количество элементов данных в очереди минус количество ожидающих потоков. Таким образом возвращаемое значение 0 может означать 'n' входов в очередь и 'n' потоков ожидания. Это может произойти или из-за блокировки очереди или из-за планирования. Функция должна вызываться во время блокировки очереди.

queue : GAsyncQueue.
Возвращает : длина очереди queue.

g_async_queue_sort_unlocked ()

void g_async_queue_sort_unlocked (GAsyncQueue *queue, GCompareDataFunc func, gpointer user_data);

Сортирует queue используя func.

Эта функция вызывается во время блокировки queue's.

queue : GAsyncQueue
func : GCompareDataFunc используемая для сортировки queue. Помещая в эту функцию два элемента queue, функция возвращает 0 если они эквивалентны, отрицательное если первый элемент должен быть выше в queue или положительное значение, если первый элемент должен быть ниже в queue чем второй элемент.
user_data : пользовательские данные для func

Начиная с версии 2.10