Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Migrating fibers between threads

Boost , Chapter 1. Fiber , Chapter 1. Fiber

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Overview

Each fiber owns a stack and manages its execution state, including all registers and CPU flags, the instruction pointer and the stack pointer. That means, in general, a fiber is not bound to a specific thread.[2],[3]

Переход волокна от логического процессора с большой рабочей нагрузкой на другой логический процессор с более легкой нагрузкой может ускорить общее выполнение. Обратите внимание, что в случае NUMA-architectures не всегда целесообразно переносить данные между потоками. Допустим, волокно f работает на логическом процессоре cpu0, который принадлежит узлу NUMA node0. Данные f распределены на физической памяти, расположенной по адресу node0. Миграция волокна от cpu0 до другого логического процессора cpuX, который является частью другого узла NUMA nodeX может снизить производительность приложения из-за увеличения задержки доступа к памяти.

Только волокна, которые содержатся в algorithm’s готовая очередь может мигрировать между нитями. Вы не можете мигрировать бегущее волокно, а также заблокировано. Вы не можете перенести волокно, если его контекст::is_context() метод возвращает True для pinned_context.

В Boost.Fiber волокно мигрируется путем ссылки контекст::detach() на резьбе, из которой волокно мигрирует, и контекст::attach() на резьбе, к которой волокно мигрирует.

Таким образом, клетчатая миграция осуществляется путем разделения состояния между экземплярами пользовательского кода algorithm, работающими на разных нитях. * пробудился()() реализация вызовов контекст::detach().

В какой-то момент, когда та же или другая нить вызывает algorithm::pick_next(), pick_next() реализация выбирает готовое волокно и звонит контекст::attach() на нем перед его возвращением.

Как указано выше, контекст для которого is_context(pinned_context) == True никогда не должен быть передан ни контекст::detach() или контекст::attach()<321>. Он может быть возвращен только из pick_next(), названного sme нити, которые передали этот контекст пробудили().

Example of work sharing

В примере work_sharing.cpp на основной нити создается множество рабочих волокон. Каждое волокно получает характер как параметр при строительстве. Этот персонаж печатается десять раз. Между каждой итерацией волокна вызывает This_fiber::yield(). Это ставит волокно в готовую очередь клетчатки shared_ready_queue, бегущую в текущей нити. Следующее волокно, готовое к исполнению, выводится из общей готовой очереди и возобновляется shared_ready_queue на любой участвующей нити.

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

Setup of threads and fibers

В main() установлен клетчатка и запущены волокна и нити.

boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); 1
for ( char c : std::string("abcdefghijklmnopqrstuvwxyz")) { 2
    boost::fibers::fiber([c](){ whatevah( c); }).detach();
    ++fiber_count; 3
}
barrier b( 4);
std::thread threads[] = { 4
    std::thread( thread, & b),
    std::thread( thread, & b),
    std::thread( thread, & b)
};
b.wait(); 5
{
    lock_t6 lk( mtx_count);
    cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); 7
} 8
BOOST_ASSERT( 0 == fiber_count);
for ( std::thread & t : threads) { 9
    t.join();
}

1

Установите алгоритм планирования boost::fibers::algo::shared_work в основной нити, поэтому каждое новое волокно запускается в общий бассейн.

2

Запустите ряд рабочих волокон; каждое рабочее волокно поднимает характер, который передается в качестве параметра клетчатке whatevah. Каждый рабочий волокно отделяется.

3

Клетчатка для каждого нового волокна.

4

Запустите пару ниточек, которые присоединяются к совместной работе.

5

синхронизация с другими потоками: позволить им начать обработку

6

lock_t std::unique_lock>< std::mutex >

7

Приостанавливает основное волокно и возобновляет рабочие волокна тем временем. Основное волокно возобновляется (например, возвращается из кондиционирование_variable_any::wait()), если все рабочие волокна завершены.

8

Перекрывающий замок mtx_count требуется перед присоединением к нити, иначе другие нити будут заблокированы внутри условия_переменные::wait() и никогда не вернутся (deadlock).

9

ждать, пока не закончится нити

Начало нитей синхронизировано с барьером. Основное волокно каждой нити (включая основную нить) приостанавливается до тех пор, пока все рабочие волокна не будут заполнены. Когда основное волокно возвращается из condition_variable::wait(), резьба заканчивается: основная резьба соединяет все остальные нити.

void thread( barrier * b) {
    std::ostringstream buffer;
    buffer << "thread started " << std::this_thread::get_id() << std::endl;
    std::cout << buffer.str() << std::flush;
    boost::fibers::use_scheduling_algorithm< boost::fibers::algo::shared_work >(); 1
    b->wait(); 2
    lock_t lk( mtx_count);
    cnd_count.wait( lk, [](){ return 0 == fiber_count; } ); 3
    BOOST_ASSERT( 0 == fiber_count);
}

1

Установите алгоритм планирования boost::fibers::algo::shared_work для присоединения к совместной работе.

2

синхронизация с другими потоками: позволить им начать обработку

3

Приостанавливает основное волокно и возобновляет рабочие волокна тем временем. Основное волокно возобновляется (например, возвращается из кондиционирование_variable_any::wait()), если все рабочие волокна завершены.

Каждое рабочее волокно выполняет функцию whatevah() с характером me в качестве параметра. Клетчатка уступает в петле и печатает сообщение, если оно было перенесено на другую нить.

void whatevah( char me) {
    try {
        std::thread::id my_thread = std::this_thread::get_id(); 1
        {
            std::ostringstream buffer;
            buffer << "fiber " << me << " started on thread " << my_thread << '\n';
            std::cout << buffer.str() << std::flush;
        }
        for ( unsigned i = 0; i < 10; ++i) { 2
            boost::this_fiber::yield(); 3
            std::thread::id new_thread = std::this_thread::get_id(); 4
            if ( new_thread != my_thread) { 5
                my_thread = new_thread;
                std::ostringstream buffer;
                buffer << "fiber " << me << " switched to thread " << my_thread << '\n';
                std::cout << buffer.str() << std::flush;
            }
        }
    } catch ( ... ) {
    }
    lock_t lk( mtx_count);
    if ( 0 == --fiber_count) { 6
        lk.unlock();
        cnd_count.notify_all(); 7
    }
}

1

получить идентификационный номер исходного потока

2

10 раз

3

выход к другим волокнам

4

получить идентификатор текущего потока

5

тест, если волокна были перенесены в другую нить

6

Клетчатка для каждого завершенного волокна.

7

Уведомить все волокна ждут на cnd_count.

Scheduling fibers

График волокна shared_ready_queue похож на round_robin, за исключением того, что он разделяет общую готовую очередь среди всех участвующих потоков. Нить участвует в этом бассейне, выполняя use_scheduling_algorithm() перед любым другим Boost.Fiber операция.

Важным моментом в готовой очереди является то, что она’ классная статичная, общая для всех случаев Share_ready_queue. Таким образом, волокна, завещанные через algorithm::awakened() (волокны, которые готовы возобновиться), доступны для всех потоков. Требуется резервировать отдельную очередь для резьбы’ основных волоконно-диспетчерских волокон: они могут не быть разделены между нити! Когда мы и #8217; прошли любой из этих волокон, нажмите его там, а не в общей очереди: это были бы плохие новости для нити B, чтобы получить и попытаться выполнить нити A’ основное волокно.

[awakened_ws]

Когда algorithm::pick_next() вызывается внутри одной нити, волокно выводится из rqueue_ и будет возобновлено в этой нити.

[pick_next_ws]

Исходный код выше содержится в work_sharing.cpp.



[2] main волокно на каждой нити, то есть волокно, на котором резьба запущена, не может мигрировать в любую другую нить. Также Boost.Fiber косвенно создает клетчатку диспетчера для каждой нити — это также не может мигрировать.

[3] Конечно, было бы проблематично перенести волокно, которое опирается на -местное хранилище.


PrevUpHomeNext

Статья Migrating fibers between threads раздела Chapter 1. Fiber Chapter 1. Fiber может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Chapter 1. Fiber ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:22:20/0.0095081329345703/0