Есть главное приложение, где выполняется отрисовка карты и траектории. А есть второстепенный поток, который читает файлы(логи) для отрисовки траектории. Как правильно передать управление из одной функции в другую? И вообще как правильнее решить этот вопрос. Вот примеры функций.
class LogReader: public QObject
{
Q_OBJECT
protected:
std::vector<Uint> m_vBlock; ///< вектор прочитанных слов
FILE* file; ///< файл загрузки (лог-файл)
public:
std::vector<ParamDescr*> rec_descr; ///< вектор параметров из файла описания (файла загрузки)
RThread* rthread; ///< указатель объект класса потока
int count_files; ///< количество непрочитанных файлов
protected:
LOGRECORD ParseBlock();
void ChangeDateTime(LOGRECORD& t, std::string compared_time, std::string compared_date);
//.............
std::vector<LOGRECORD> TRead();
};
/// Чтение файла загрузки
vector<LOGRECORD> LogReader::TRead()
{
Uint var = (Uint)1E+6;
bool bBlock = false;
bool file_read = false;
vector<LOGRECORD> log;
time_t before_read;
time(&before_read);
while(fread(&var, sizeof(var), 1, file) > 0 && !feof(file))
{
Suint adr = var % 256;
/// Определение начала/конца одной записи и записывание ее в вектор
switch(adr)
{
case 0000:
m_vBlock.clear();
bBlock = true;
break;
case 0001:
if(bBlock)
{
LOGRECORD t = ParseBlock();
ChangeDateTime(t, "cur_time", "cur_date");
log.push_back(t);
file_read = true;
/// Сравнение временных меток
time_t contin_read;
time(&contin_read);
time_t delta = contin_read - before_read;
if(delta > 5)
{
rthread -> stop();
//rthread -> wait(1000);
}
}
bBlock = false;
break;
default:
if(bBlock)
m_vBlock.push_back(var);
}
}
/// Закрываем файл с логом
ShutDown();
/// Уменьшаем список непрочитанных файлов
if(file_read)
{
--count_files;
rthread -> stop();
}
return log;
}
class RThread: public QThread
{
Q_OBJECT
private:
enum { MAXRECENTFILES = 7 };
volatile bool stopped; ///< переменная, контролирующая начало и конец выполнения потока
QMutex mutex; ///< мьютекс для блокировки данных при работе с ними дополнительного потока
public:
Reader::LogReader* logger; ///< объект для чтения логов
std::vector<LOGRECORD> read_log;///< вектор LOGRECORD , в котором находятся значения из считанного файла
protected:
void run();
public:
RThread(): stopped(false) {}
void stop();
};
/// Запуск дополницельного потока
void RThread::run()
{
forever
{
mutex.lock();
if(stopped)
{
stopped = false;
mutex.unlock();
break;
}
read_log = logger -> TRead();
mutex.unlock();
}
//QThread::run();
}
/// Остановка дополнительных потоков
void RThread::stop()
{
mutex.lock();
stopped = true;
mutex.unlock();
}
if(delta > 5)
{
rthread -> stop();
//rthread -> wait(1000);
}
Если я тебя правильно понял, то rthread->start();
Но ИМХО лучше не в run передовать, а в какую-нибудь другую функцию данного потока посредством сигналов и слотов.
Ну с сигналами и слотами все достаточно просто.
Создаем сигнал (threadSignal) и слот (threadSlot) и связываем их:
connect( this, SIGNAL( threadSignal), pObject, SLOT( threadSlot));
emit threadSignal();
connect( this, SIGNAL( threadSignal), pObject, SLOT( threadSlot));
emit threadSignal();
Думаю, что в твоем варианте примерно так:
class LogReader: public QObject
{
// ...
LogReader();
protected signals:
void threadSignal();
// ...
};
LogReader::LogReader()
{
// ...
connect( this, SIGNAL( threadSignal), rthread, SLOT( threadSlot)); // разумеется rthread должен быть валидным.
}
class RThread: public QThread
{
// ...
public slots:
void threadSlot();
// ...
};
void RThread::threadSlot()
{
// Здесь что-то делается...
}
Ну и вызываешь emit threadSignal(); в том участке коде, что показывал в первом посте...
Спасибо за помощь!
АААА. Еще не все.
Сделал.
Выдает ошибку -
Error: Signals cannot have access specifier
Определение для сигнала не нужно, оно генерируется автоматически moc'ом.
В какой строчке выдает ошибку?
protected signals:
void threadSignal();
AD22, ты где сигнал посылаешь (emit threadSignal()) можешь пример привести?
vector<LOGRECORD> LogReader::TRead()
{
//......................
while(fread(&var, sizeof(var), 1, file) > 0 && !feof(file))
{
Suint adr = var % 256;
/// Определение начала/конца одной записи и записывание ее в вектор
switch(adr)
{
case 0000:
m_vBlock.clear();
bBlock = true;
break;
case 0001:
if(bBlock)
{
LOGRECORD t = ParseBlock();
ChangeDateTime(t, "cur_time", "cur_date");
log.push_back(t);
file_read = true;
/// Сравнение временных меток
time_t contin_read;
time(&contin_read);
time_t delta = contin_read - before_read;
if(delta > 5)
emit threadSignal();
}
bBlock = false;
break;
default:
if(bBlock)
m_vBlock.push_back(var);
}
}
//..................
return log;
}
Теперь ошибка при выполнении. Ломается программа на строчках:
LogReader::LogReader(std::string FileName)
{
fopen_s(&file, FileName.c_str(), "rb");
connect(this, SIGNAL(threadSignal()), rthread, SLOT(threadSlot()));
}
тема такая, высылать сигнал может только тот класс в котором сигнал определен, я так понял что он у тебя в другом классе, тогда сделай так:
class LogReader: public QObject
{
// ...
LogReader();
protected signals:
void threadSignal();
public:
void sendMySignal()
{
emit threadSignal();
}
// ...
};
class LogReader: public QObject
{
// ...
LogReader();
protected signals:
void threadSignal();
public:
void sendMySignal()
{
emit threadSignal();
}
// ...
};
на то он и форум
Понял в чем проблема, но не знаю как выправить.
Смысл такой в функции LogReader::TRead() в месте вызова сигнала я хочу, чтобы в вектор read_log добавлялись считанные значения, а в слоте я опять же обращаюсь к функции TRead() для того, чтобы вернуть этот вектор. Как это сделать, подскажите, пожалуйста!
приведи код, просто не совсем понятно, что ты хочешь.
/// Чтение файла загрузки
vector<LOGRECORD> LogReader::TRead()
{
Uint var = (Uint)1E+6;
bool bBlock = false;
bool file_read = false;
vector<LOGRECORD> log;
time_t before_read;
time(&before_read);
while(fread(&var, sizeof(var), 1, file) > 0 && !feof(file))
{
Suint adr = var % 256;
/// Определение начала/конца одной записи и записывание ее в вектор
switch(adr)
{
case 0000:
m_vBlock.clear();
bBlock = true;
break;
case 0001:
if(bBlock)
{
LOGRECORD t = ParseBlock();
ChangeDateTime(t, "cur_time", "cur_date");
log.push_back(t);
file_read = true;
/// Сравнение временных меток
time_t contin_read;
time(&contin_read);
time_t delta = contin_read - before_read;
/*if(delta > 5)
emit threadSignal();*/
}
bBlock = false;
break;
default:
if(bBlock)
m_vBlock.push_back(var);
}
}
/// Запуск дополницельного потока
void RThread::run()
{
forever
{
mutex.lock();
if(stopped)
{
stopped = false;
mutex.unlock();
break;
}
mutex.unlock();
read_log = logger -> TRead();
}
}
/// Остановка дополнительных потоков
void RThread::stop()
{
mutex.lock();
stopped = true;
mutex.unlock();
}
/// Слот, в который попадаем в момент чтения лог-файла
void RThread::threadSlot()
{
mutex.lock();
read_log = logger -> TRead();
mutex.unlock();
}
time_t contin_read;
time(&contin_read);
time_t delta = contin_read - before_read;
if(delta > 5)
emit threadSignal();
А добавить RThread::run работает?
void RThread::run()
{
// ...
exec();
}
Насчет остального не могу сейчас сказать, так как голова совсем уже не соображает.
Нет не работает. В смысле, не выводится траектория!!! Буду благодарен за любой дельный совет.
Слушай можешь выложить исходники с файлом который ты читаешь в архиве, я полностью гляну, что у тебя и как там?
А то вопросов слишком много...
И в кратце обьясни, что есть, что нужно.
Вот файлы. При выполнении предлагается выбрать вначале ини файл. Затем лог-файл. Ини-файл - начальные данные, Лог-файл - данные, полученные с прибора.
P.S. ини файл надо выбирать TTVPlane.ini
Проблема вроде бы решена. ВСЕМ СПАСИБО! Если будут другие проблемы - буду обращаться
Ну вот, а я только взялся за рассмотрение твоего кода...
Чтобы хоть?
Вопрос на будущее. Мне пришлось "убивать"(delete) поток и создавать заново. А как его остановить?
void QThread::quit()
или
void QThread::exit ( int returnCode = 0 )
просто вызвать
У меня есть огромная просьба: проблема, которая обсуждалась в этой теме уже давно решена. Но решена не совсем методами Qt. Если у кого-то есть хороший, яркий, понятный пример использования мьютексов и дополнительных потоков, пожалуйста, выложите здесь!!! Примеры, которые приведены в книжке Бланшетта на эту тему чересчур просты! Просьба пример привести посложнее, чем в книге и яркий!
P.S. Просто нашел в программе места, где было бы удобно использовать доп. поток, а внятного применения приведенных в книге примеров найти не смог!
Ты просто по всей видимости не доконца понимаешь как работаю процессы и потоки.
Почитай книжку Джеффри Рихтера http://archival.ru/?q=node/10, в ней хорошо описана работа с процессами, потоками и их синхронизация, хоть и на WinApi, но достаточно хорошо разжеваны все аспекты...
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)