На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела *nix / gcc / Eclipse / Qt / wxWidgets / GTK+
  • При создании темы ОБЯЗАТЕЛЬНО указывайте версию тулкита / библиотеки / компилятора.
  • Перед тем как задать вопрос, сформулируйте его правильно, чтобы вас могли понять.
  • Нарушение Правил может повлечь наказание со стороны модераторов.


Полезные ссылки:
user posted image Boost по-русски
user posted image Qt по-русски
Модераторы: archimed7592
  
> Работа с QThread , вызов функции в отдельном потоке в произвольные моменты времени
    Здравствуйте.
    Как сделать, чтобы определённая функция-член наследника от QThread исполнялась всегда в этом новом потоке, который экземпляром моего класса-наследника инкапсулируется?
    Как я понял, есть два метода: 1) объявить её как слот, соединить с каким-нибудь сигналом другого класса и активировать сигнал по необходимости, 2) использовать QMetaObject::invokeMethod. В обоих случаях в конструкторе наследника надо вызвать moveToThread(this).
    Делают ли так, как я описал, или есть другие методы, которые и надо использовать в этом случае?

    PS функция принимает два параметра, вызов её в принципе возможен из многих потоков, возможно что и одновременно. То есть проверка QWaitCondition и вызов функции из run() не пойдёт, я так понимаю.
    Сообщение отредактировано: Санчес -
      ExpandedWrap disabled
        class MyThread : public QThread
        {
            MyThread( int param1, int param2 )
            : mParam1( param1 )
            , mParam2( param2 )
            {
            }
            virtual void run( )
            {
                needCallInThread( mParam1, mParam2 );
            }
            static void needCallInThread( int, int );
            int mParam1;
            int mParam2;
        };


      Главная проблема это то, что функция, которую нужно вызвать является членом QThread ( потому что сам объект QThread принадлежит другому потоку и его слоты вызываются в другом потоке ). Если она была бы членом какого-нибудь друго класса, который создан в этом QThread и наследуемый от QObject, было бы проще.
      Сообщение отредактировано: sploid -
        Я неточно выразился. Поток создаётся и начинает работать. В произвольный момент из другого потока может потребоваться вызвать функцию, причём выполниться она должна в этом потоке.
        Конкретно - функция слежения за изменениями файлов в каталоге. Вызывает функцию WinAPI ReadDirectoryChangesW, заявляя, что мы следим за определённым каталогом на диске. ОС может при обнаружении изменений вызвать callback-функцию, которая была ранее зарегистрирована вызовом ReadDirectoryChangesW.
        Поток при этом работает так - в течение секунды крутится в exec(), потом по таймеру поступает сигнал quit(). Поток выходит из exec() и вызывает SleepEx (разрешает callback-вызовы). Далее, если надо, система вызывает callback-функцию для обработки изменений. Заканчивается SleepEx и поток опять идёт в exec(). И так далее.
        Класс QFileSystemWatcher знаю, но он не подходит: там по сигналу directoryChanged нет возможности определить, какое изменение произошло в каталоге (добавился ли новый файл, был ли файл удалён или переименован, или просто изменено содержимое).

        Так вот. Чтобы система вызывала callback-функцию, надо, чтобы поток вошёл в alertable-состояние вызовом SleepEx. А поскольку это делает вторичный, а не главный поток, то и вызов ReadDirectoryChangesW должен происходить во вторичном потоке.

        Добавлено
        Ещё можно попробовать обойтись без обратных вызовов и вызывать GetOverlappedResult (но тогда надо создавать дополнительный event на каждый наблюдаемый каталог) или GetQueuedCompletionStatus (тогда надо создавать completion port на каждый наблюдаемый каталог)...
          т.е. только во время работы SleepEx ОС может вызвать callback и причем callback будет вызван в контексте потока, где осуществлен вызов SleepEx?
            Цитата sploid @
            т.е. только во время работы SleepEx ОС может вызвать callback и причем callback будет вызван в контексте потока, где осуществлен вызов SleepEx?

            В контексте какого потока (вторичного или вообще какого-то служебного) будет вызван callback, я не проверял, да это пока и не принципиально.
            Но SleepEx для активизации callback'a должен делать именно тот поток, который вызвал ReadDirectoryChangesW. Вот поэтому мне надо эти два вызова совместить в одном потоке.

            Добавлено
            Кстати, один рецепт придумал - создавать в run() объект, в конструкторе которого будет вызов ReadDirectoryChangesW. Но при этом для наблюдения за N каталогами потребуется N потоков...
              ExpandedWrap disabled
                static MyObj* my_obj = NULL
                // функция, которая вызывается системой при изменении папки
                void system_callback( )
                {
                    my_obj->call_in_callback( );
                }
                // поток запуска мониторинга изменения директории
                class MyThread : public QThread
                {
                    MyThread( ) : want_stop( false )  {  };
                    virtual void run( )
                    {
                        ReadDirectoryChangesW...
                        while ( !want_stop )
                        {
                             SleepEx....
                        }
                    };
                    bool want_stop;
                };
                // объект, который крутиться в отдельном потоке и метод которого вызывается при калл-беке.
                class MyObj : public QObject
                {
                    Q_OBJECT
                    MyObj( )
                    {
                        my_obj = this;
                        connect( this, SIGNAL( signal_call_in_thread( ) ), SLOT( on_call_in_thread( ) ) );
                    };
                public:
                    // вызывается из системного колл-бэка
                    void call_in_callback( )
                    {
                        emit signal_call_in_thread( );
                    }
                public slots:
                    // эта функция будет вызвана в отдельном потоке
                    void on_call_in_thread( )
                    {
                    }
                signals:
                    // сигнал нужен что бы слот был вызван в отдельном потоке, в котором создан объект
                    void signal_call_in_thread( );
                };
                class MyThread : public QThread
                {
                    virtual void run( )
                    {
                        MyObj obj;
                        exec( );
                    }
                };
              Сообщение отредактировано: sploid -
                Не понял, как это у тебя два класса с именем MyThread?
                  сорри, косяк ( код я не компилировал, просто показывал идею ).
                  последний класс надо назвать как-нибудь по другому.

                  Суть кода в том что объект MyObj создается в отдельном потоке и его слот будет вызван в этом потоке, и неважно из какого потока был сгенерен сигнал.
                  А самый первый поток нужен что бы зарегистрировать колл-бэк для вызова при изменении директории и ожидать этого изменения ( т.к. ты сказал что колл-бек будет вызван только если поток в SleepEx ).
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0348 ]   [ 16 queries used ]   [ Generated: 28.04.24, 13:44 GMT ]