Russian Qt Forum

Qt => Вопросы новичков => Тема начата: deefox от Август 10, 2016, 11:09



Название: Указатели
Отправлено: deefox от Август 10, 2016, 11:09
Доброго времени суток.

Столкнулся с такой ситуацией. Есть главное окно MainWindow, от него выделена память на поток приема информации asio, а от потока приема еще один поток обработки информации(конкретнее отрисовка пикселей в QImage)

Еще от главного окна выделил новый класс для работы с QGrapgicsView. Суть вопроса в том, что я создал массив QImage [16] и хочу передать адрес напрямую в поток обработки, для того чтобы при отрисовки, он сразу или через некоторое время отрисовывал на экран. Создавал в MainWindow и в каждом классе делал указатели, но либо ошибки, либо крашится при запуске. подскажите как лучше сделать.

сейчас картина такая


Код:
for (int i = 0; i < 16; i++){
        viewmap->img[i] = &img[i];
        asio->imagethread->image[i] = &img[i];
    }



Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 11:17
Никаких указателей, GUI должен обновляться по таймеру.
В этом обработчике таймера сделайте защищенный доступ к вашим картинкам.
Читаете данные и пакуете на GUI.


Название: Re: Указатели
Отправлено: deefox от Август 10, 2016, 11:26
Никаких указателей, GUI должен обновляться по таймеру.
В этом обработчике таймера сделайте защищенный доступ к вашим картинкам.
Читаете данные и пакуете на GUI.


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


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 11:29
А "всё" и не надо, только апдейт гуя раз 5 в секунду (чаще все равно обычно нет смысла).


Название: Re: Указатели
Отправлено: deefox от Август 10, 2016, 11:33
А "всё" и не надо, только апдейт гуя раз 5 в секунду (чаще все равно обычно нет смысла).


то есть вы предлагаете, не использовать отдельно класс при работе с виджетом QGraphicView, создать в гуи и единственное что,  нужно будет передать указатель в поток обработки ?

Код:
for (int i = 0; i < 16; i++){
        asio->imagethread->image[i] = &img[i];
    }

и работать непосредственно в MainWindow?


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 12:09
В MainWindow ничего не надо делать.
В вашем наследнике QGraphicView надо запустить таймер, а в обработчик timeout вставить код, который будет читать данные из asio->imagethread и отображать их на сцене.
Естественно, читаемые данные в imagethread должны быть защищены мьютексом.


Название: Re: Указатели
Отправлено: Igors от Август 10, 2016, 12:18
С таким "емким" названием темы "суть вопроса" не ясна  :). Но в любом случае указатели здесь не помогают, а вредят. Здесь выгоднее прокатиться на имплисит шаре и обойтись без всяких защит. Допустим Вы получили картинку в нитке чтения - ну и пошлите ее по значению сигналом в главную, напр
Код
C++ (Qt)
void SignalSetImage( QImage img );
Главная нитка обновит UI, может спокойно удалять/менять полученный img. То же самое для посылающей. За счет шары копирование состоится только при изменении


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 12:24
Допустим Вы получили картинку в нитке чтения - ну и пошлите ее по значению сигналом в главную

Так нельзя делать, от слова "вообще".
Во-первых, частота обновления картинок в нитке может быть очень высокой - в итоге поток гуя "забьется" сигналами и не справится с обработкой, в итоге зависнет наглухо.
Во-вторых, в этом случае нет никакой гарантии, что посылаемый объект не будет изменён во время "простоя" в очереди на обработку. Придётся перед отправкой сигнала делать img.detach(), т.е. deep copy, что опять же ударит по производительности.
Поэтому единственный нормальный вариант - позволить гую самому решать, когда ему обновляться. А это тока через таймер.


Название: Re: Указатели
Отправлено: Igors от Август 10, 2016, 12:44
Во-вторых, в этом случае нет никакой гарантии, что посылаемый объект не будет изменён во время "простоя" в очереди на обработку. Придётся перед отправкой сигнала делать img.detach(), т.е. deep copy, что опять же ударит по производительности.
Давайте подробнее. Имедж послан по значению и пока где-то сохранен (QueuedConnection). Да, хранимая копия пока ссылается на те же данные пикселей что и исходный имедж. Теперь посыпающая нитка замещает имедж другим. Ну тогда-то шара и сработает, сама сделает detach, хранимая копия останется со старыми данными, оригинал получит новые, все будет исполнено атомарно. Так что гарантия есть. 

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


Название: Re: Указатели
Отправлено: qate от Август 10, 2016, 12:51
поток приема информации asio

а чего не нативный qthread ?


Название: Re: Указатели
Отправлено: deefox от Август 10, 2016, 14:10
поток приема информации asio

а чего не нативный qthread ?


Я его использую, просто boost asio udp крутится в этом потоке, а так обычный QThread.

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

Цитировать
В MainWindow ничего не надо делать.
В вашем наследнике QGraphicView надо запустить таймер, а в обработчик timeout вставить код, который будет читать данные из asio->imagethread и отображать их на сцене.
Естественно, читаемые данные в imagethread должны быть защищены мьютексом.

Наследник от QGraphicView, а не от MainWindow, и как ему читать данные, не имея указателя? желательно не используя сигналы, а на прямую?

Это и была суть вопроса, извините, наверно невнятно все описал.


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 14:15
Да, хранимая копия пока ссылается на те же данные пикселей что и исходный имедж. Теперь посыпающая нитка замещает имедж другим. Ну тогда-то шара и сработает, сама сделает detach, хранимая копия останется со старыми данными, оригинал получит новые, все будет исполнено атомарно. Так что гарантия есть. 

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


Название: Re: Указатели
Отправлено: Old от Август 10, 2016, 14:20
Тут нет никакой гарантии. Сами на подобное натыкались.

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

Код
C++ (Qt)
uchar *QImage::scanLine(int i)
{
   if (!d)
       return 0;
 
   detach();
 
   // In case detach() ran out of memory
   if (!d)
       return 0;
 
   return d->data + i * d->bytes_per_line;
}
 


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 14:31
uchar* linePtr = img.scanLine(0); // тут detach, понятно

linePtr[0] = 0xff;

emit ImageChanged(img); // ушел сигнал...

linePtr[0] = 0xaa; // а тут поменяли - detach в пролете

emit ImageChanged(img); // снова ушел сигнал, но теперь кто есть кто - вопрос...


Название: Re: Указатели
Отправлено: Old от Август 10, 2016, 14:32
uchar* linePtr = img.scanLine(0); // тут detach, понятно

linePtr[0] = 0xff;

emit ImageChanged(img); // ушел сигнал...

linePtr[0] = 0xaa; // а тут поменяли - detach в пролете

emit ImageChanged(img); // снова ушел сигнал, но теперь кто есть кто - вопрос...


Вам не кажется, что за такое нужно переводить в разносчики кофе. :)


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 14:36
Вам не кажется, что за такое нужно переводить в разносчики кофе. :)

Поэтому я и предлагаю через таймер обновляццо :)


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 14:38
Наследник от QGraphicView, а не от MainWindow, и как ему читать данные, не имея указателя? желательно не используя сигналы, а на прямую?

Через интерфейс, который вернет необходимые данные.
Типа
QImage GetLastImage();

Добавьте этот метод в ваш класс потока и вызывайте его из гуя по таймеру.
В методе возвращайте последнюю полученную картинку.



Название: Re: Указатели
Отправлено: Igors от Август 10, 2016, 15:18
Просто хочется сделать проще, без копирования, и прочего, получил, отрисовал в определнныйх полотнах QImagе, и выдал на экран.

...желательно не используя сигналы, а на прямую?
При взаимодействии 2 и более ниток "напрямую" ничего не делается. Так или иначе главной надо "забрать" имедж, и указатель здесь никак не поможет - все равно надо знать что имедж валиден, его можно рисовать. Др словами синхронизация все равно нужна. И вообще имплисит шара - фундаментальная фича Qt, напрасно Вы так небрежно к ней относитесь.

Оригинальные пиксели легко могут быть изменены через поинтер, полученный через QImage::scanLine (как чаще всего и делается), при этом никакой detach() не вызовется.
Только ручками, только хардкор :)
Даже если полезли в пыксели (о чем разговора не было) - передернуть затвор никто не мешал
Код
C++ (Qt)
uchar* linePtr = img.scanLine(0); // тут detach, понятно
linePtr[0] = 0xff;
emit ImageChanged(img); // ушел сигнал...
linePtr = img.scanLine(0);  
...
 


Название: Re: Указатели
Отправлено: qate от Август 10, 2016, 15:34
я бы делал так:
1. QUdpSocket и в его событии приема рисовал бы (сразу или N раз в сек)

2. Если вариант 1 тормозит, то
2.1 QUdpSocket и в его событии приема сбор данных в QByteArray
2.2 По накоплению данных (или какому иному условию) - старт потока обработки(рендеренга) или через QtConcurent
2.3 Данные обработаны - сигнал в основной поток с этими данными для отрисовки



Название: Re: Указатели
Отправлено: deefox от Август 10, 2016, 16:10
я бы делал так:
1. QUdpSocket и в его событии приема рисовал бы (сразу или N раз в сек)

2. Если вариант 1 тормозит, то
2.1 QUdpSocket и в его событии приема сбор данных в QByteArray
2.2 По накоплению данных (или какому иному условию) - старт потока обработки(рендеренга) или через QtConcurent
2.3 Данные обработаны - сигнал в основной поток с этими данными для отрисовки



QUdpSocket очень плохо принимает данные, поэтому и использую boost.

но все примерно так и есть
Всем спасибо, познал очень много с темы.


Название: Re: Указатели
Отправлено: Racheengel от Август 10, 2016, 16:20
QUdpSocket очень плохо принимает данные, поэтому и использую boost.

Могу спросить, что за проблемы были выявлены с QUdpSocket ?


Название: Re: Указатели
Отправлено: qate от Август 10, 2016, 16:46
QUdpSocket очень плохо принимает данные, поэтому и использую boost.

какой багрепорт это подтверждает ?