Однократно вызываемые функции 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Однократно вызываемые функции



Остается разобраться с одним вопросом: как сделать функции инициализации (такие как конструкторы) потокобезопасными. Например, когда «глобальный» экземпляр объекта создается как синглетон уровня приложения (единственный существующий в приложении объект данного типа), существует проблема порядка инстанцирования, поэтому используется функция, возвращающая статический экземпляр, которая гарантирует, что при первом к ней обращении этот экземпляр будет создан. Проблема в том, что если несколько потоков одновременно вызовут эту функцию, конструктор для статического объекта также может быть вызван несколько раз, и результаты могут оказаться плачевными.

Решение проблемы в так называемых «однократно вызываемых функциях» (once routine). Такая функция вызывается в приложении только один раз. Если несколько потоков попытаются ее вызвать одновременно, только один из них получит такую возможность, а в это время все остальные потоки будут ждать, пока выполнение функции не завершится. Чтобы гаранти ровать однократное выполнение, такая функция вызывается косвенно через другую функцию, которой передается указатель на исходную и ссылка на специальный флаг, сигнализирующий о факте вызова функции. Этот флаг инициализируется статически, что гарантирует инициализацию в период компиляции, а не в период выполнения. И таким образом не представляет проблемы для многопоточной инициализации. Библиотека Boost.Threads предоставляет возможность однократного вызова функции посредством boost::call_once, а также определяет тип для флага boost::once_flag и специальную макроподстановку, используемую для статической инициализации флага, BOOST_ONCE_INIT.

Пример 6 показывает очень простой пример использования boost::call_once. Глобальное целое статически инициализируется нулем, а экземпляр boost::once_flag статически инициализируется с помощью BOOST_ONCE_INIT. Основной поток запускает два потока, каждый из которых пытается «инициализировать» глобальное целое, вызывая boost::call_once с указателем на функцию, инкрементирующую целое. Затем основной поток дожидается завершения обоих потоков и выводит конечное значение целого в std::cout. Вывод демонстрирует, что функция действительно была вызвана только однажды, так как значение целого – единица.

 

// Пример 6

#include <boost/thread/thread.hpp>

#include <boost/thread/once.hpp>

#include <iostream>

int i = 0;

boost::once_flag flag = BOOST_ONCE_INIT;

void init()

{

++i;

}

void thread()

{

boost::call_once(&init, flag);

}

int main(int argc, char* argv[])

{

boost::thread thrd1(&thread);

boost::thread thrd2(&thread);

thrd1.join();

thrd2.join();

std::cout << i << std::endl;

return 0;

}

 

Инициализация параметров

Есть ещё классная штука - возможность инициализировать параметры, запустив функцию однократно. Например, есть три потока, которые обращаются к переменной х, но сперва её надо инициализировать, причём только один раз, а не всеми тремя потоками сразу. Для этого предусмотрен специальный механизм:

int i;

boost::once_flag flag = BOOST_ONCE_FLAG;

void init()

{

i = 0;

}

void thread()

{

boost::call_once(&init, flag);

// дальнейший код

}

Так вот, инициализация произойдёт всего один раз, независимо от числа конкурирующих потоков.

Ожидание внутри потоков

Иногда надо подождать немного в потоке. Для этого есть два разных способа

· boost::this_thread::sleep(params)

· boost::this_thread::yield()

Первый (с установленными параметрами) замораживает поток на указанное время.

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

 

 



Поделиться:


Последнее изменение этой страницы: 2016-12-11; просмотров: 236; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.188.20.56 (0.007 с.)