Russian Qt Forum

Qt => Общие вопросы => Тема начата: IUnknown от Февраль 12, 2007, 18:43



Название: Синхронизация потоков
Отправлено: IUnknown от Февраль 12, 2007, 18:43
У меня есть QList<Data*> m_list. В нем содержатся Data два вида данных - которые быстро получаются, а другие после долгих вычислений (интерполяции). Есть список где нужно отобразить обе переменные. Я решил в наследнике QAbstractTableModel в методе data их отображать. Нужно сделать так что-бы после того как я заполняю список данными, те что долго считаются подгружались в отдельном потоке.
Не могу никак сделать так что-бы можно было не закончив старую загрузку сново начать новую - выбрасывает ошибку index out of range.

добавлено спустя 11 минут:

 Я прочитал то что написал и сам не понял что я написал. Вот код:
Код:
class Data
{
...
Data()
{
...
}
...

QString dataFast;
QString dataSlow;
bool bIsLoaded;
};

QVariant QDataListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role == Qt::DisplayRole)
{
Data* pData = static_cast<Data*>(m_List.at(index.row()));
if (index.column() == 0)
{
  return pData->dataFast;
}
else if (index.column() == 1)
{
if(pData->bIsLoaded)
return pData->dataSlow;
else return QVariant();
}
}
return QVariant();
}

QVariant QDataListModel::GetData(const QString data)
{
thread->Stop();
while(!thread->wait());
LoadData(&m_List);
thread->start();
}

QLoaderThread::QLoaderThread(QObject *parent)
: QThread(parent)
{
m_bStop = false;
}

QLoaderThread::~QLoaderThread()
{

}

void QLoaderThread::run()
{
m_mutex.lock();
m_bStop = false;
QDataListModel* pModel = qobject_cast<QDataListModel*>(this->parent());
for(int i=0; i<=pModel->m_List.count()-1; i++)
{
if(m_bStop)
{
break;
}
Data* pData = static_cast<Data*>(pModel->m_List[i]);
pData->dataSlow = GetSlowData(pData->fastData);
                        pData->bIsLoaded = true;
pData = 0;
emit pModel->reset();
}
pModel = 0;
m_mutex.unlock();
}

void QLoaderThread::Stop()
{
m_mutex.lock();
if(!m_bStop) m_bStop = true;
m_mutex.unlock();
}
[/code]


Название: Синхронизация потоков
Отправлено: mcgeenerman от Февраль 14, 2007, 23:36
на скока я знаю QList очень схож с std::list и он не безопасен в плане потоков,  дело в том что в листе доступ к элементам последователный, что и влечёт ошибку доступа к элементу одновременно,
я бы использовал шаблон связанных контейнеров - например std::set<_T>, в Qt, QSet<_T> аналогично, вообще в Qt переписан практически stl, я не проверял твой код но по задачи так выходит, я сталкивался с подобной ошибкой.


Название: Синхронизация потоков
Отправлено: IUnknown от Февраль 15, 2007, 21:32
QSet не пробовал, но боюсь что он может не подойти, так как я очень часто использую перегруженый оператор []. По числу ответов понял что наверное не очень правильно пояснил. Все кто видели как работаю wdx плагины для TotalCommander-а поймут что мне нужно. Если в списке вы создаете колонку которая например загружает инфу из тегов музыкальных файлов, то она появляется последовательно по мере извлечения, при том что список файлов уже отобразился. И если вы переходите в другую папку, пока информация для всего списка еще не загружена, то тот поток останавляивается и начинается новый для другой директории. Мне нужно организовать похожий список, только даные в потоке будут подгружатся из базы и с нимим будут проводится манипуляции, а уде после этого они будут вставлятся в список.
Буду благодарен за любую информацию, а то программа стоит на месте.


Название: Синхронизация потоков
Отправлено: nova от Февраль 15, 2007, 22:16
Из всего написанного я понял только одно, ты пытаешся обратится к не распределенным данным:)
По моему тут все просто.
1. читаеш быстрые данные, получаеш сформированный список в котором dataSlow.isNull() == TRUE && bIsLoaded == FALSE.
2.Для ентих данных запускаеш поток который мееедлеееенно  читает dataSlow
3. после чтения dataSlow для записи делаеш для большей безопасности кода
Код:

mutex.lock();
bIsLoaded =TRUE;
mutex.unlock();

Мутекс описываеш в class Data.
4. вмодели делаеш проверку
Код:

if(!p->mutex.tryLock () && pData->bIsLoaded)
    return pData->dataSlow;
else return QVariant();

опятьже для большей безопасноси ;)


при необходимости преостанавливаеш поток медленного чтения
1. читаеш новые быстрые данные
2. запускаеш новый поток чтения медленных
3. не забываеш отслеживать парент для новых данных :)

и так далее

Я так понял у тебя данные в виде дерева :)


Название: Синхронизация потоков
Отправлено: mcgeenerman от Февраль 15, 2007, 22:20
я просмотрел твой код, не совсем всё понял так как он не полноценный, но я вижу бреш в доступе к переменной члена класса, ты пишеш:
Код:
pModel->m_List[i]
, тоесть доступ к члену класса происходит напрямую, что не очень хорошо. Я предлагаю тебе создать метод, а в методе создать мутекс для контроля за пользованием указателя, так например QList<Data*>* getList(); и второй метод освобождения пользования releaseList(); так как доступ к данным листа нельзя производить из разных потоков одновременно, что и влёчёт ошибку index out of range, особенно это в тех случаях когда используеш оператор [], на нём и происходит сбой,(я так думаю), тут всё из за добавления элемента, если ты добавляеш элемент в список то доступ к элементам в этот же момент будет критичным так как список перенастраевается, тем более он ещё и двунапрявленный. тоесть когда ты вызываеш оператор [] то он ищет элемен итеративным методом а не рямым как это было бы в QMap::operator[], но тут QMap <_Key, _Temp>, если _Key создать как int например QMap <int,Data*> mymap, то доступ к элементу mymap, причём доступ моментальный,скорость 2^N, в отличии от QList скорость доступа N, но добавление элмента достаточно долгое, так как map это бинарное дерево, так же как и QSet, только в QSet нет _Temp.  вообщем решай как тебе легче сделать, и так и так код нада менять достаточно много как я понимаю.