Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
Pechkin80
12 / 10 / 4
Регистрация: 14.03.2014
Сообщений: 162
#1

Универсальная передача аргументов в потоках boost::thread - C++

07.10.2017, 23:58. Просмотров 206. Ответов 6
Метки нет (Все метки)

Пишу обертку для потока и не могу организовать универсальную передачу аргументов, чтоб когда надо передовался по ссылке, а когда надо по значению. С stl потоками работает, если делать как сказано тут
а с бустом не хочет. Может кто знает где собака зарыта. Для краткости определение деструктора не привожу.

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class ManagedThread
{
   using bthread = boost::thread;
public:
   explicit ManagedThread():mActive( false) {}
   template<typename Function,typename... Args>
   void Binder( Function&& f,Args&&... _args);
   ~ManagedThread();
   bool isActive() const { return mActive; }
   bool isRunning() const
   {
       return atomic_load(&m_isRunning);
   }
   //ManagedThread() = delete;
   ManagedThread(const ManagedThread&) = delete;
   ManagedThread(const ManagedThread &&) = delete;
   ManagedThread& operator=(const ManagedThread&) = delete;
   ManagedThread& operator=(const ManagedThread&&) = delete;
private:
   volatile bool  mActive;
   //std::thread    mThread;
   /// Указатель на объект потока
   bthread * m_pthread;
   /// Флаг работы основного цикла потока
   std::atomic<bool> m_isRunning;
   void stop()
   {
       atomic_store(&m_isRunning, false);
   }
};
 
template< class Function, class... Args>
   void threadFunction( volatile bool& active_flag, Function& f, Args&&... args)
{
   active_flag = true;
   //f( std::forward<Args...>(args...));
   active_flag = false;
}
 
template<typename Function,typename... Args>
void   ManagedThread::Binder( Function&& f,Args&&... _args)
{
 
    m_pthread = new bthread(threadFunction<Function,Args...>,
                boost::ref(mActive),
                boost::ref(f),
                _args...);
    //std::thread * t1 = new std::thread(threadFunction<typename std::decay<Function>::type>,
    //                  std::ref(mActive),
    //                  std::forward<Function>(f));
    //threadFunction<Function>(mActive,std::forward<Function>(f));
}
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.10.2017, 23:58
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Универсальная передача аргументов в потоках boost::thread (C++):

Передача переменного числа аргументов в функцию - Visual C++
Всем доброго времени суток! При написании класса столкнулся со следующей проблемой: в классе есть функция, которая провторяет работу...

Не могу найти ошибку.Универсальная программа тестирования. - Visual C++
Здравствуйте.Написал программу,вроде все правильно но выдает ошибку.Не могу сам разобраться.Это универсальная программа тестирования.Вот...

Многопоточный чат (Threads) на С++ - C++ WinAPI
Всем добрый вечер. Прошу извинения если тему разместил не в том разделе, т.к. я долго на эту тему колебался. Суть вопроса следующая:...

передача аргументов - C++
Здравствуйте,объясните пожалуйста,на примерах кода,что означает передача аргументов по ссылке, по значению,передача копий аргументов?

Передача аргументов в ф-ию - C++
void test(const T&amp; a) {} Это понятно, а что это за запись: void test(T const&amp; a) {} И как понять ссылку на ссылку,...

Передача аргументов функции - C++
В книге Стенли Липпмана C++ Primer дошел до программы, которая выполняет замену слов в одном файле, которые указаны в другом. Например, ...

6
notAll
424 / 145 / 35
Регистрация: 27.05.2016
Сообщений: 387
Завершенные тесты: 2
08.10.2017, 17:50 #2
С бустом не проверял, но мне кажется, что правильная реализация должна быть примерно такая:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <thread>
#include <functional>
#include <utility>
 
class ManagedThread
{
public:
    ManagedThread() = default;
    ManagedThread(const ManagedThread&) = delete;
    ManagedThread(const ManagedThread&&) = delete;
    ManagedThread& operator=(const ManagedThread&) = delete;
    ManagedThread& operator=(const ManagedThread&&) = delete;
 
    ~ManagedThread()
    {
        if (mThread.joinable())
            mThread.join();
    }
 
    template <typename Function, typename... Args>
    void Binder(Function&&, Args&&...);
 
private:
    std::thread mThread;
    volatile bool  mActive {false};
};
 
template <class Function, class... Args>
void threadFunction(volatile bool& active_flag, Function&& f, Args&&... args)
{
    active_flag = true;
    f(std::forward<Args>(args)...);
    active_flag = false;
}
 
template <typename Function, typename... Args>
void ManagedThread::Binder(Function&& f, Args&&... _args)
{
 
    mThread = std::move(std::thread(threadFunction<Function, Args...>, std::ref(mActive),
                                    std::forward<Function>(f), std::forward<Args>(_args)...));
 
}
 
void foo(int i, const std::string& text)
{
    std::cout << i << " " << text << "\n";
}
 
 
int main()
{
    ManagedThread mt;
    mt.Binder(&foo, 42, std::string("Hello"));
}
0
Pechkin80
12 / 10 / 4
Регистрация: 14.03.2014
Сообщений: 162
10.10.2017, 11:47  [ТС] #3
Проблема решена.
Дело не в коде было.
Но конечный вариант привожу ниже
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifndef THREAD_H
#define THREAD_H
#include "common.h"
#include "error.h"
/// Таймаут ожидания при удаления потока
#define THREAD_TIMEOUT 250
 
class ManagedThread
{
   using bthread = boost::thread;
public:
   explicit ManagedThread():mActive( false) {m_pthread = nullptr;}
   template<typename Function,class Class, typename... Args>
   void Binder( Function&& f,Class&& obj, Args&&... _args);
   ~ManagedThread();
   bool isActive() const { return mActive; }
   bool isRunning() const
   {
       return atomic_load(&m_isRunning);
   }
   void Start()
   {
       atomic_store(&m_isRunning, true);
   }
   ManagedThread(const ManagedThread&) = delete;
   ManagedThread(const ManagedThread &&) = delete;
   ManagedThread& operator=(const ManagedThread&) = delete;
   ManagedThread& operator=(const ManagedThread&&) = delete;
private:
   volatile bool  mActive;
   /// Указатель на объект потока
   bthread * m_pthread;
   /// Флаг работы основного цикла потока
   std::atomic<bool> m_isRunning;
   void stop()
   {
       atomic_store(&m_isRunning, false);
   }
};
 
template< class Function, class Class, class... Args>
   void threadFunction(Function&& f,  Class&& obj, Args&&... _args)
{
   //active_flag = true;
   (obj->*f)(boost::forward<Args>(_args)...);
   //active_flag = false;
}
 
template<typename Function,class Class, typename... Args>
void   ManagedThread::Binder(Function&& f,Class&& obj, Args&&... _args)
{
 
    m_pthread = new bthread(threadFunction<Function, Class, Args...>,
                boost::forward<Function>(f),
                boost::forward<Class>(obj),
                boost::forward<Args>(_args)...);
}
 
#endif // THREAD_H
Добавлено через 7 часов 51 минуту
Для решения проблемы пришлось сделать 4 вещи:
1)Установить версию mingw32-64 4.8.3 так как полноценная поддержка вариативных шаблонов в буст потоках начиная с 4.8.1
2)Заново откомпилировать буст новым компилятором
3)Изменить натройки IDE Qt creator под новый компилятор
4)Изменить параметр BOOST_THREAD_VERSION в файле ./boost/thread/detail/config.hpp значение 4 (по умолчанию 2)
Программа компилируется со ВТОРОГО раза, а на первый получаю вот такую бяку:

D:\work\build-exness\lib\libboost_thread-mgw48-mt-1_55.a(thread.o):-1: ошибка: duplicate section `.data$_ZZN5boost16exception_detail27get_static_exception_objectINS0_14bad_exception_EEENS_13exception_ptrEvE2ep[__ZZN5boost16exception_detail27get_static_exception_objectINS0_14bad_exception_EEENS_13exception_ptrEvE2ep]' has different size
D:\work\build-exness\lib\libboost_thread-mgw48-mt-1_55.a(thread.o):-1: ошибка: duplicate section `.data$_ZZN5boost16exception_detail27get_static_exception_objectINS0_10bad_alloc_EEENS_13exception_ptrEvE2ep[__ZZN5boost16exception_detail27get_static_exception_objectINS0_10bad_alloc_EEENS_13exception_ptrEvE2ep]' has different size
D:\work\build-exness\lib\libboost_thread-mgw48-mt-1_55.a(thread.o):-1: ошибка: duplicate section `.data$_ZGVN5boost16exception_detail37exception_ptr_static_exception_objectINS0_14bad_exception_EE1eE[__ZGVN5boost16exception_detail37exception_ptr_static_exception_objectINS0_14bad_exception_EE1eE]' has different size

Уже устал ковыряться в бустовской канализации.
0
Operok
162 / 160 / 44
Регистрация: 15.02.2015
Сообщений: 464
Завершенные тесты: 2
10.10.2017, 12:40 #4
В поток (std::thread / boost::thread) нельзя передавать параметры по ссылке (хоть универсальной), только по значению.
0
Pechkin80
12 / 10 / 4
Регистрация: 14.03.2014
Сообщений: 162
10.10.2017, 12:58  [ТС] #5
Operok, Обоснуйте пожалуйста. Ваше утверждение выглядит нелепым.
boost/thread.hpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
        template <class F, class Arg, class ...Args>
        thread(F&& f, Arg&& arg, Args&&... args) :
          thread_info(make_thread_info(
              thread_detail::decay_copy(boost::forward<F>(f)),
              thread_detail::decay_copy(boost::forward<Arg>(arg)),
              thread_detail::decay_copy(boost::forward<Args>(args))...)
          )
 
        {
          start_thread();
        }
0
Operok
162 / 160 / 44
Регистрация: 15.02.2015
Сообщений: 464
Завершенные тесты: 2
10.10.2017, 16:10 #6
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
М.б. неверно выразился, передавать вы можете как вам угодно, только это всё будет скопировано в объект потока.
Boost.Thread tutorial
Для std::thread искать не буду, для этой темы не актуально.
1
Pechkin80
12 / 10 / 4
Регистрация: 14.03.2014
Сообщений: 162
10.10.2017, 17:45  [ТС] #7
Operok, Ну так для этого классы обертки и существуют: boost::forward, boost::ref, boost::cref
Так как речь идёт о универсальной передачи, то используется boost::forward.

Добавлено через 13 минут
Operok, Я вам открою секрет, я использую в качестве аргумента Args... args ссылку на объект класса с удалённым конструктором копирования и содержащим внутри атомарные переменные. Если это по значению передавать, то будет мат перемат))))

Добавлено через 2 минуты
Operok, Пардон, не только там классы обертки, но и функции обертки.

Добавлено через 16 минут
Operok, По поводу вами приведённой ссылки, то хорошо читать до конца:
C++
1
2
3
4
5
6
7
Thread Constructor with arguments
 
template <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);
 
Preconditions:
F and each An must be copyable or [B]movable[/B].
Добавлено через 22 минуты
Operok, Хотя конечно есть правда в ваших словах. но практика критерий истины. У меня работает. Возможно при перемещении задействуется както передача по ссылке. Я глубоко в потрохах не копался.

Добавлено через 10 минут
Возможно, я недокументированные возможности использую, так как я менял значение BOOST_THREAD_VERSION в коде. Он нигде не описан.
0
10.10.2017, 17:45
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.10.2017, 17:45
Привет! Вот еще темы с ответами:

Передача аргументов в функцию - C++
При сборке кода выдает ошибку (её я написал в комментарий). Что значит ошибка? #include &lt;iostream&gt; #include &lt;math.h&gt; using...

Передача аргументов в функцию - C++
Доброго всем дня! Я немного не понял листинг программы из учебника Р.Лафоре: #include&quot;stdafx.h&quot; #include&lt;iostream&gt; ...

Передача аргументов в программу - C++
Хочу передать аргументы в программу, если использовать такую сигнатуру: int _tmain(int argc, _TCHAR* argv) //---------------- ...

Передача аргументов в функцию - C++
Что сработает быстрее? void Func(const A &amp;a = A(0, 0, 0)) { } или void Func(A a = A(0, 0, 0))


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru