Параллельное программирование на С++ в действии. Практика разработки многопоточных программ | страница 28



, и отсоединяем его (2). Поскольку новый поток делает то же самое, что текущий, только с другим файлом, то мы можем использовать ту же функцию (>edit_document), передав ей в качестве аргумента имя только что выбранного файла.

Этот пример демонстрирует также, почему бывает полезно передавать аргументы функции потока: мы передаем конструктору объекта >std::thread не только имя функции (1), но и её параметр — имя файла. Существуют другие способы добиться той же цели, например, использовать не обычную функцию с параметрами, а объект-функцию с данными-членами, но библиотека предлагает и такой простой механизм.

2.2. Передача аргументов функции потока

Из листинга 2.4 видно, что по существу передача аргументов вызываемому объекту или функции сводится просто к передаче дополнительных аргументов конструктору >std::thread. Однако важно иметь в виду, что по умолчанию эти аргументы копируются в память объекта, где они доступны вновь созданному потоку, причем так происходит даже в том случае, когда функция ожидает на месте соответствующего параметра ссылку. Вот простой пример:

>void f(int i, std::string const& s);

>std::thread t(f, 3, "hello");

Здесь создается новый ассоциированный с объектом >t поток, в котором вызывается функция >f(3, "hello"). Отметим, что функция >f принимает в качестве второго параметра объект типа >std::string, но мы передаем строковый литерал >char const*, который преобразуется к типу >std::string уже в контексте нового потока. Это особенно важно, когда переданный аргумент является указателем на автоматическую переменную, как в примере ниже:

>void f(int i, std::string const& s);


>void oops(int some_param) {

> char buffer[1024];           ←(1)

> sprintf(buffer, "%i", some_param);

> std::thread t(f, 3, buffer);(2)

> t.detach();

>}

В данном случае в новый поток передается (2) указатель на локальную переменную >buffer(1), и есть все шансы, что выход из функции oops произойдет раньше, чем буфер будет преобразован к типу >std::string в новом потоке. В таком случае мы получим неопределенное поведение. Решение заключается в том, чтобы выполнить преобразование в >std::stringдо передачи >buffer конструктору >std::thread:

>void f(int i,std::string const& s);


>void not_oops(int some_param) {

> char buffer[1024];                         │Использование

> sprintf(buffer, "%i", some_param);         │std::string

> std::thread t(f, 3, std::string(buffer)); ←┘позволяет избежать

> t.detach();