Svoboda | Graniru | BBC Russia | Golosameriki | Facebook

Для установки нажмите кнопочку Установить расширение. И это всё.

Исходный код расширения WIKI 2 регулярно проверяется специалистами Mozilla Foundation, Google и Apple. Вы также можете это сделать в любой момент.

4,5
Келли Слэйтон
Мои поздравления с отличным проектом... что за великолепная идея!
Александр Григорьевский
Я использую WIKI 2 каждый день
и почти забыл как выглядит оригинальная Википедия.
Статистика
На русском, статей
Улучшено за 24 ч.
Добавлено за 24 ч.
Альтернативы
Недавние
Show all languages
Что мы делаем. Каждая страница проходит через несколько сотен совершенствующих техник. Совершенно та же Википедия. Только лучше.
.
Лео
Ньютон
Яркие
Мягкие

Из Википедии — свободной энциклопедии

setcontext — одна из библиотечных функций стандарта POSIX (в число других входят getcontext, makecontext и swapcontext), используемая для управления контекстом. Семейство setcontext позволяет реализовать на языке Си такие паттерны проектирования управления потоком, как итераторы, нити (fibers) и сопрограммы. Семейство можно рассматривать как расширенную версию setjmp/longjmp; в то время как последние позволяют только один нелокальный прыжок из стека, setcontext позволяет создание нескольких взаимодействующих потоков управления с собственными стеками.

Спецификация

setcontext определён в POSIX.1-2001 и во второй версии Single UNIX Specification, однако доступен не во всех UNIX-подобных операционных системах. Функции и связанные с ними типы определены в заголовочном файле ucontext.h. В их число входит тип ucontext_t, с которым взаимодействуют все четыре функции:

typedef struct ucontext {
	struct ucontext *uc_link;
	sigset_t uc_sigmask;
	stack_t uc_stack;
	mcontext_t uc_mcontext;
	...
} ucontext_t;

uc_link указывает на контекст, который будет восстановлен при выходе из текущего контекста, если контекст создан с помощью makecontext (вторичный контекст). uc_sigmask используется для хранения сигналов, заблокированных в контексте, а uc_stack является стеком, используемым контекстом. uc_mcontext используется для хранения состояния исполнения, включая все регистры центрального процессора, счётчик команд и указатель стека; mcontext_t является непрозрачным (opaque) указателем.

Также определены следующие функции:

  • int setcontext(const ucontext_t *ucp)
Эта функция переносит управление в контекст в ucp. Исполнение продолжается с точки, на которой контекст был сохранён в ucp. В случае успешного выполнения возврата из setcontext не производится.
  • int getcontext(ucontext_t *ucp)
Сохраняет текущий контекст в ucp. Возврат из этой функции происходит в двух случаях: после первичного вызова или при переключении потока на контекст в ucp с помощью setcontext или swapcontext. Функция getcontext не предоставляет возвращаемого значения для разделения этих случаев (оно служит лишь для сообщения об ошибке), поэтому разработчик должен явным образом использовать переменную-флаг, объявленную без модификатора register и с модификатором volatile во избежание свёртывания константных выражений и других оптимизаций компилятора.
  • void makecontext(ucontext_t *ucp, void *func(), int argc, ...)
Функция makecontext устанавливает альтернативный поток управления в ucp, предварительно инициализированный с помощью getcontext. Поле ucp.uc_stack должно указывать на место для стека необходимого размера; обычно используется константа SIGSTKSZ. При совершении прыжка в ucp с помощью setcontext или swapcontext исполнение начинается с точки входа в функцию func с числом аргументов argc. При завершении func управление передаётся ucp.uc_link.
  • int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
Передаёт управление ucp и сохраняет текущее состояние выполнения в oucp.

Пример

Пример ниже демонстрирует итератор, реализованный с помощью setcontext. Подобный код можно встретить достаточно редко; вместо использования setcontext для реализации кооперативной многозадачности часто используется различные библиотеки-обёртки, например, GNU Portable Threads.

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>

/* Функция-итератор. Вход в неё осуществляется при первом вызове
 * swapcontext, затем проходит в цикле от 0 до 9. Каждое значение сохраняется 
 * i_from_iterator, после чего производится возврат в основной цикл с помощью swapcontext. 
 * В основном цикле производится вывод значения и вызов swapcontext для возврата
 * назад в функцию. При достижении конца цикла исполнение переключается на контекст main_context1*/
void loop(
    ucontext_t *loop_context,
    ucontext_t *other_context,
    int *i_from_iterator)
{
    int i;
    
    for (i=0; i < 10; ++i) {
        /* Запись счётчика цикла в место возврата итератора. */
        *i_from_iterator = i;
        
        /* Сохранение контекста цикла в ''loop_context'' и переключение на другой контекст. */
        swapcontext(loop_context, other_context);
    }
} 
 
int main(void)
{
    /* Три контекста:
     *    (1) main_context1 : указывает на main для возврата из цикла.
     *    (2) main_context2 : указывает на место переключения контекста в main
     *    (3) loop_context  : указывает на место в цикле, в которое будет 
     *                        переходить управление из main. */
    ucontext_t main_context1, main_context2, loop_context;
    
    /* Стек для функции итератора. */
    char iterator_stack[SIGSTKSZ];

    /* Флаг, сообщающий о завершении итератора. */
    volatile int iterator_finished;
   
    /* Возвращаемое значение итератора. */
    volatile int i_from_iterator;
   
    /* Инициализация контекста итератора. uc_link указывает на main_context1, 
     * точку возврата при завершении итератора. */
    loop_context.uc_link          = &main_context1;
    loop_context.uc_stack.ss_sp   = iterator_stack;
    loop_context.uc_stack.ss_size = sizeof(iterator_stack);
    getcontext(&loop_context);
    
    /* Заполнение loop_context, что позволяет swapcontext начать цикл. 
     * Преобразование в (void (*)(void)) необходимо для избежания  предупреждения 
     * компилятора и не влияет на поведение функции. */
    makecontext(&loop_context, (void (*)(void)) loop,
        3, &loop_context, &main_context2, &i_from_iterator);
   
    /* Очистка флага завершения. */      
    iterator_finished = 0;

    /* Сохранения текущего контекста в main_context1. При завершении цикла
     * управление будет возвращено в эту точку. */
    getcontext(&main_context1);
  
    if (!iterator_finished) {
        /* Установка флага iterator_finished для отключения перезапуска итератора. */
        iterator_finished = 1;
       
        while (1) {
            /* Сохранение этой точки в main_context2 и переключение на итератор.
             * Первый вызов зачинает цикл, последующие осуществляют переключение
             * через swapcontext в цикл. */
            swapcontext(&main_context2, &loop_context);
            printf("%d\n", i_from_iterator);
        }
    }
    
    return 0;
}

Примечание: данный пример не соответствует справочной странице спецификации [1]. Функция makecontext требует, чтобы дополнительные параметры были типа int, а в примере передаются указатели. Это может привести к ошибке на 64-битных платформах (в частности, на архитектурах LP64, где sizeof(void*) > sizeof(int)). Теоретически эти проблемы могут быть решены, но эти решения также не являются портируемыми.

Примечания

  1. The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition. Дата обращения: 30 июля 2010. Архивировано 9 декабря 2010 года.

Ссылки

Эта страница в последний раз была отредактирована 18 мая 2022 в 16:14.
Как только страница обновилась в Википедии она обновляется в Вики 2.
Обычно почти сразу, изредка в течении часа.
Основа этой страницы находится в Википедии. Текст доступен по лицензии CC BY-SA 3.0 Unported License. Нетекстовые медиаданные доступны под собственными лицензиями. Wikipedia® — зарегистрированный товарный знак организации Wikimedia Foundation, Inc. WIKI 2 является независимой компанией и не аффилирована с Фондом Викимедиа (Wikimedia Foundation).