LINUX.ORG.RU

Как реализовать в qt работу с QList нескольким потокам для записи и чтения ?

 , ,


0

1

Есть не сколько потоков в программе, один обновляет QList, может удалять в нем элементы и добавлять. Остальные только читают. QList объявлен глобально в классе, который занимается обновлением его. В другие потоки передавал по ссылке QList для чтения, сейчас сделал по значению передачу. Но прога иногда каким-то случайным образом падает. Во всех классах для чтения QList проверяется его размер и соответственно нету выхода за пределы массива вроде как.

Вот из-за чего падает каким-то случайным образом и как такой баг отловить ?

Вот из-за чего падает каким-то случайным образом и как такой баг отловить ?

QList не thread-safe. Потому и падает.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Так падало и по ссылке когда передача. А можешь объяснить почему падает. Падает в классах чтения обычно на самых первых обращениях к QList на методах size(). Так как в классах чтения что-то типа такого

list = myClass_writen->GetList();

for(int i=0;i<list->size();i++)
{
   qDebug() << "list" << list.at(i);
}
user2132
() автор топика
Ответ на: комментарий от ox55ff

А какие есть варианты thread-safe вместо QList. Правильно ли понимаю, что в моменты, когда класс2 очищает QList нельзя даже к этому объекту делать методы типа size, length или проверки на Null. Кстати также класс2 иногда делает delete QList и потом заново его создает. В классе1 стоят проверки типа:

if(mylist == NULL)
{
  qDebug() << "null mylist"
  return;
}

Но это не ловит, указатель на mylist обычно имеет какой-то адрес, ведущий в несуществующую память и при вызове любого метода после прога падает. Правильно ли понимаю, что перед delete надо сделать mylist = NULL; чтобы класс1 поймал его, когда QList разрушен и не начал с ним работать.

user2132
() автор топика
Ответ на: комментарий от user2132

А какие есть варианты thread-safe вместо QList.

Я тебе уже два раза написал про мьютекс. Ты специально игнорируешь? Просто защити доступ к QList с помощью мьютекса.

Правильно ли понимаю

Да.

if(mylist == NULL)

Это не поможет. При многопоточном исполнении другой поток может вклиниться в любой момент.

МЬЮТЕКС!!!!1111

ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 1)
Ответ на: комментарий от user2132

Правильно ли понимаю, что перед delete надо сделать mylist = NULL;

Нет, так у тебя будет утечка памяти.

ox55ff ★★★★★
()
Ответ на: комментарий от user2132

Кстати также класс2 иногда делает delete QList и потом заново его создает.

Кстати, зачем? Вызвать метод clear нельзя?

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Не знаю, код достался от другого прогера. Про мьютексы: объявляю QMutex mutex; и делаю его доступным классам 1 и 2. И в обоих где работа с QList ставлю в начале метода mutex.lock(); и в конце mutex.unlock();

Этого достаточно будет ?

user2132
() автор топика
Ответ на: комментарий от user2132

Концептуально да, правильно.

в начале метода mutex.lock(); и в конце mutex.unlock();

Лучше использовать QMutexLocker locker(&mutex); в начале метода. И старайся максимально уменьшить область действия мьютекса, чтобы снизить время блокировки ожидающих потоков. Но это так, на будущее.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Да про QMutexLocker нашел пример. А правильно понимаю, что сигналами и слотами передача между потоками будет thread-safe и только в этом случае можно работать без мьютекса, не опасаясь креша ?

user2132
() автор топика
Ответ на: комментарий от user2132

Смотря как ты сделаешь. Будет копироваться объект или отдаваться по указателю и т.д. Ещё нужно учитывать тип соединения: прямое или через очередь. Без контекста сказать трудно.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Я про вариант, когда QList list; emit send(list); то есть копирую, связь типа так connect(this,&Class1::send,class2,&Class2::getlist_slot); Я так понимаю когда connect без флага Qt::directConnection, то это безопасный вариант в этом случае.

user2132
() автор топика
Ответ на: комментарий от user2132

В момент emit send(list); с листом должен работать только один поток.

Я так понимаю когда connect без флага Qt::directConnection

Нет, по умолчанию там Qt::AutoConnection. Это автоматическое определение. Если и отправитель и получатель сигнала находятся в одном потоке, то будет Qt::directConnection, иначе Qt::queuedConnection. Принадлежность объекта к потоку меняется через метод moveToThread. Посмотри, у тебя есть перемещение потока? Или лучше явно задай тип при вызове метода connect.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Примерно так хочу сделать: class1_write

QList list;
QMutex mutex;

QList Getmylist()
{
  QMutexLocker locker(&mutex); 
  return list;
}

void change()
{
   QMutexLocker locker(&mutex);
   list.clear();
   //наполняю list далее тут
}

А в class2_read:

void fun_parse_list()
{
   QMutexLocker locker(&class1_obj->mutex); //надо ли тут или достаточно в Getmylist поставить mutex.
   QList mylist = class1_obj->Getmylist();
   qDebug() << mylist;
}

Достаточно ли так применять mutex блокировку только внутри методов class1_write ?

user2132
() автор топика
Ответ на: комментарий от ox55ff

возможно без мьютекса будет лучше - пусть в гуевый тред засылает сигналы на которые подпишет модель, которая засетена во вьюху, так ему лишь нужно доработать модель под свои нужды, а стандартное поведение связки модели и вьюхи само все отрисует как надо.

deep-purple ★★★★★
()
Ответ на: комментарий от user2132

да, засылай сигналом в модель копии данных, у тебя будут сл сигналы: лист очищен (модель чистит свой), элемент добавлен (передать строку, модель добавляет к себе), элемент удален (передать индекс), элемент изменен (передать в сигнале индекс и новое строковое).

deep-purple ★★★★★
()
Ответ на: комментарий от user2132

Мьютекс в fun_parse_list не нужен. Ты же скопировал объект.

ox55ff ★★★★★
()
Ответ на: комментарий от deep-purple

Я смутно представляю его архитектуру. Если читающим потокам отправлять копию и отправкой (вызов emit) будет заниматься пишущий поток, то можно и без мьютекса. Но тогда инициировать отправку нужно будет через сигнал с Qt::queuedConnection.

ox55ff ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.