Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите понять boost::thread
Форум на CrossPlatform.RU > Библиотеки > boost
igor_bogomolov
Всем привет.
Начал потихоньку осваивать boost. Возникло несколько вопросов.

Имею примерно такой код
MSK.h
#include <boost/thread/thread.hpp>

class MSK {
public:
    MSK();
protected:
    static void RoutinePnP();
private:
    boost::thread _pnpthread;
};
MSK.cpp
#include <iostream>
#include <boost/thread/xtime.hpp>

MSK::MSK()
{
    _pnpthread = boost::thread(&RoutinePnP);
}

void MSK::RoutinePnP()
{
    for(;;) {
        std::cout << "PnP run..." << std::endl;

        // приостанавливаем поток на 10 секунд
        boost::xtime xt;
        boost::xtime_get(&xt, boost::TIME_UTC);
        xt.sec += 10;
        boost::thread::sleep(xt);
    }
}
main

int main()
{
    MSK msk;

    std::cout << "message1" << std::endl;
    std::cout << "message2" << std::endl;
    std::cout << "message3" << std::endl;
    std::cout << "message4" << std::endl;

    while(1) sleep(1);
    return EXIT_FAILURE;
}



В результате получаю:
Цитата
PnP run...
message1 \
message2 | Эти сообщения я получаю только через 10 секунд
message3 | т.е. основной поток получается заблоктрованным
message4 /
PnP run...
PnP run...
PnP run...
PnP run...
и т.д....



1) Где и что я делаю не правильно. Почему блокируется основной поток? Или это просто доступ к самой консоли блокируется?
2) Как нормально приостановить поток средствами boost, не привязываясь к системному времени.
3) Что делать если RoutinePnP у меня не может быть статической? Есть ли возможность передать в поток не статический метод класса? Или тут единственный вариант - создавать глобальный метод и делать его дружественным для класса MSK?
--------------------------------------------
4) (не по теме) Где то читал что в boost есть аналог Q_PROPERTY(...), что то не могу найти. (((
Andrew Selivanov
Я бы рекомендовал для начала изучить неплохие примеры из Thread: C:\boost\boost_1_37_0\libs\thread\example\

На третий вопрос отвечу кодом из примера про голодных философов (starvephil.cpp):
class thread_adapter
{
public:
    thread_adapter(void (*func)(void*), void* param)
        : _func(func), _param(param)
    {
    }
    void operator()() const { _func(_param); }
private:
    void (*_func)(void*);
    void* _param;
};


Привязываем потоки к конкретным объектам через thread_adapter и делаем join (join грубо говоря обозначает не убивать этот поток пока не завершаться присоединённые к нему потоки, у тебя эту роль играет вечный sleep())
    phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
    boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
    boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
    boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
    boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
    boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));


    thrd_phil0.join();
    thrd_phil1.join();
    thrd_phil2.join();
    thrd_phil3.join();
    thrd_phil4.join();


Цитата
2) Как нормально приостановить поток средствами boost, не привязываясь к системному времени.

Насколько я помню никак

Цитата
1) Где и что я делаю не правильно. Почему блокируется основной поток? Или это просто доступ к самой консоли блокируется?


MinGW 3.4.5/Boost 1.37
Ничего нигде не блокируется.
Я обычно что то в этом духе делаю:
#include <iostream>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread.hpp>

//для SetConsoleCtrlHandler ...
#include <windows.h>

class MSK {
public:
    MSK() : is_running(false)
    {

    }

    void run()
    {
        is_running = true;
        while(is_running)
        {
            std::cout << "PnP run...\n";

            // приостанавливаем поток на 10 секунд
            boost::xtime xt;
            boost::xtime_get(&xt, boost::TIME_UTC);
            xt.sec += 10;
            boost::thread::sleep(xt);
        }
        std::cout << "[run] ok\n";
    }

    void stop()
    {
        is_running = false;
    }

    static void do_thread(void* param)
    {
        static_cast<MSK*>(param)->run();
    }

private:
    bool is_running;
};

class thread_adapter
{
public:
    thread_adapter(void (*func)(void*), void* param)
        : _func(func), _param(param)
    {
    }
    void operator()() const { _func(_param); }
private:
    void (*_func)(void*);
    void* _param;
};

MSK msk;

BOOL WINAPI stop_handler(DWORD ctrl_type)
{
    switch (ctrl_type)
    {
    case CTRL_C_EVENT:
    case CTRL_BREAK_EVENT:
    case CTRL_CLOSE_EVENT:
    case CTRL_SHUTDOWN_EVENT:
        std::cout << "waiting to stop...\n";
        msk.stop();
        return TRUE;
    default:
        return FALSE;
    }
}

int main()
{
    std::cout << "[start]\n";

    boost::thread msk_thrd(thread_adapter(&MSK::do_thread, &msk));

    SetConsoleCtrlHandler(&stop_handler, TRUE);

    msk_thrd.join();

    std::cout << "[stop]\n";

    return 0;
}
true_goth
Цитата(igor_bogomolov @ 27.7.2009, 22:58) *
Всем привет.
Начал потихоньку осваивать boost. Возникло несколько вопросов.

Имею примерно такой код
MSK.h
#include <boost/thread/thread.hpp>

class MSK {
public:
    MSK();
protected:
    static void RoutinePnP();
private:
    boost::thread _pnpthread;
};
MSK.cpp
#include <iostream>
#include <boost/thread/xtime.hpp>

MSK::MSK()
{
    _pnpthread = boost::thread(&RoutinePnP);
}

void MSK::RoutinePnP()
{
    for(;;) {
        std::cout << "PnP run..." << std::endl;

        // приостанавливаем поток на 10 секунд
        boost::xtime xt;
        boost::xtime_get(&xt, boost::TIME_UTC);
        xt.sec += 10;
        boost::thread::sleep(xt);
    }
}
main

int main()
{
    MSK msk;

    std::cout << "message1" << std::endl;
    std::cout << "message2" << std::endl;
    std::cout << "message3" << std::endl;
    std::cout << "message4" << std::endl;

    while(1) sleep(1);
    return EXIT_FAILURE;
}



В результате получаю:
Цитата
PnP run...
message1 \
message2 | Эти сообщения я получаю только через 10 секунд
message3 | т.е. основной поток получается заблоктрованным
message4 /
PnP run...
PnP run...
PnP run...
PnP run...
и т.д....



1) Где и что я делаю не правильно. Почему блокируется основной поток? Или это просто доступ к самой консоли блокируется?
2) Как нормально приостановить поток средствами boost, не привязываясь к системному времени.
3) Что делать если RoutinePnP у меня не может быть статической? Есть ли возможность передать в поток не статический метод класса? Или тут единственный вариант - создавать глобальный метод и делать его дружественным для класса MSK?
--------------------------------------------
4) (не по теме) Где то читал что в boost есть аналог Q_PROPERTY(...), что то не могу найти. (((


нужный код найдешь тут, безо всяких тридадаптеров, у буст есть спецовая boost::bind для таких целей, мне очень пригодилась
Iron Bug
во-первых, в какой системе работаешь и какой компилятор?
далее, по пунктам:
1. это неноральное поведение, поток никак не может блокироаться в данном случае. 37-й буст - довольно старая версия. возможно, потоки были доработаны с тех пор. хотя я не сталкивалась с подобным глюком, но это может оказаться глюком библиотеки. возьми для начала новый буст.
также обязательно проверь, что компилишь проект с опциями мультипоточности (это важно, буст может работать неправильно, если эти опции не включены).

2. что значит "не привязываясь к системному времени? this_thread::sleep принимает и абсолютное, и относительное время. это перегруженная функция и можно скармливать ему и абсолютно время, и интервалы в формате posix_time::seconds, posix_time::microseconds, и т.д., в зависимости от возможностей твоей системы и макросов, которые ты указал для сборки.

3. создавай функтор с оператором operator() и передавай его. а в нём юзай что хочешь.
igor_bogomolov
Iron Bug, спасибо за помощь, но тема достаточно устарела и ответы я давно получил )
Iron Bug
а, не заметила даты. просто последний ответ был вчера. поэтому подумала, что тема новая. ну ладно, пусть будет.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.