Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.89] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте.
Как сделать, чтобы определённая функция-член наследника от QThread исполнялась всегда в этом новом потоке, который экземпляром моего класса-наследника инкапсулируется? Как я понял, есть два метода: 1) объявить её как слот, соединить с каким-нибудь сигналом другого класса и активировать сигнал по необходимости, 2) использовать QMetaObject::invokeMethod. В обоих случаях в конструкторе наследника надо вызвать moveToThread(this). Делают ли так, как я описал, или есть другие методы, которые и надо использовать в этом случае? PS функция принимает два параметра, вызов её в принципе возможен из многих потоков, возможно что и одновременно. То есть проверка QWaitCondition и вызов функции из run() не пойдёт, я так понимаю. |
Сообщ.
#2
,
|
|
|
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, было бы проще. |
Сообщ.
#3
,
|
|
|
Я неточно выразился. Поток создаётся и начинает работать. В произвольный момент из другого потока может потребоваться вызвать функцию, причём выполниться она должна в этом потоке.
Конкретно - функция слежения за изменениями файлов в каталоге. Вызывает функцию WinAPI ReadDirectoryChangesW, заявляя, что мы следим за определённым каталогом на диске. ОС может при обнаружении изменений вызвать callback-функцию, которая была ранее зарегистрирована вызовом ReadDirectoryChangesW. Поток при этом работает так - в течение секунды крутится в exec(), потом по таймеру поступает сигнал quit(). Поток выходит из exec() и вызывает SleepEx (разрешает callback-вызовы). Далее, если надо, система вызывает callback-функцию для обработки изменений. Заканчивается SleepEx и поток опять идёт в exec(). И так далее. Класс QFileSystemWatcher знаю, но он не подходит: там по сигналу directoryChanged нет возможности определить, какое изменение произошло в каталоге (добавился ли новый файл, был ли файл удалён или переименован, или просто изменено содержимое). Так вот. Чтобы система вызывала callback-функцию, надо, чтобы поток вошёл в alertable-состояние вызовом SleepEx. А поскольку это делает вторичный, а не главный поток, то и вызов ReadDirectoryChangesW должен происходить во вторичном потоке. Добавлено Ещё можно попробовать обойтись без обратных вызовов и вызывать GetOverlappedResult (но тогда надо создавать дополнительный event на каждый наблюдаемый каталог) или GetQueuedCompletionStatus (тогда надо создавать completion port на каждый наблюдаемый каталог)... |
Сообщ.
#4
,
|
|
|
т.е. только во время работы SleepEx ОС может вызвать callback и причем callback будет вызван в контексте потока, где осуществлен вызов SleepEx?
|
Сообщ.
#5
,
|
|
|
Цитата sploid @ т.е. только во время работы SleepEx ОС может вызвать callback и причем callback будет вызван в контексте потока, где осуществлен вызов SleepEx? В контексте какого потока (вторичного или вообще какого-то служебного) будет вызван callback, я не проверял, да это пока и не принципиально. Но SleepEx для активизации callback'a должен делать именно тот поток, который вызвал ReadDirectoryChangesW. Вот поэтому мне надо эти два вызова совместить в одном потоке. Добавлено Кстати, один рецепт придумал - создавать в run() объект, в конструкторе которого будет вызов ReadDirectoryChangesW. Но при этом для наблюдения за N каталогами потребуется N потоков... |
Сообщ.
#6
,
|
|
|
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( ); } }; |
Сообщ.
#7
,
|
|
|
Не понял, как это у тебя два класса с именем MyThread?
|
Сообщ.
#8
,
|
|
|
сорри, косяк ( код я не компилировал, просто показывал идею ).
последний класс надо назвать как-нибудь по другому. Суть кода в том что объект MyObj создается в отдельном потоке и его слот будет вызван в этом потоке, и неважно из какого потока был сгенерен сигнал. А самый первый поток нужен что бы зарегистрировать колл-бэк для вызова при изменении директории и ожидать этого изменения ( т.к. ты сказал что колл-бек будет вызван только если поток в SleepEx ). |