Russian Qt Forum
Июнь 16, 2024, 04:47 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Бросает исключение в потоке  (Прочитано 6057 раз)
blood_shadow
Гость
« : Апрель 20, 2011, 20:12 »

Вот только недавно начал шариться с потоками и попал на такую ситуацию:
есть поток с такой ф-цией run:
Код
C++ (Qt)
void FilesAttachementManage::run()
{
   forever
   {
       QFileInfo fileInfo;
 
       {
           QMutexLocker locker(&filesReadMutex);
 
           if (readFilesQueue.isEmpty())
               filesAdded.wait(&filesReadMutex);
           fileName = readFilesQueue.dequeue();
       }
 
       fileInfo.setFile(fileName);
       quint64 size = fileInfo.size();
 
       if (commonFileSize + size > MAX_ATTACHED_SIZE)
       {
           readFilesQueue.clear();
           qDebug() << "continue";
           continue;
       }
 
       QFile file(fileName);
       if (!file.open(QIODevice::ReadOnly))
       {
 
           qDebug() << "file don't open -> " << fileName;
           continue;
 
       }
 
       commonFileSize += size;
       listOfEncodedFiles->append(file.readAll().toBase64());
 
       qDebug() << "at end";
   }
}
 

run() - запускается с конструктора данного объекта и останавливается (filesAdded.wait(&filesReadMutex))
когда readFilesQueue - очередь пуста
и есть ф-ция для добавления в очередь:

Код
C++ (Qt)
void FilesAttachementManage::readFiles(const QStringList &fileNames)
{
   filesReadMutex.lock();
 
   foreach (QString file, fileNames)
       readFilesQueue.enqueue(file);
 
   filesReadMutex.unlock();
 
   filesAdded.wakeOne();
 
}
 

после добавления больших файлов где-то 300Мб на втором из них программа завершается
с ошибкой(Invalid parameter passed to C runtime function.) и более того она кидает
исключение std::bad_alloc, происходит это в районе ф-ции
listOfEncodedFiles->append(file.readAll().toBase64());
listOfEncodedFiles - указатель на список кодированных строк, если же добавлять маленькие
файлы то все нормально, в чем может быть проблема?
Записан
Sancho_s_rancho
Гость
« Ответ #1 : Апрель 20, 2011, 20:54 »

На первый взгляд все нормально. Вы пытаетесь загрузить 300 мб в память(да еще и несколько таких файлов), и перекодировать в base64(на это тоже нужно место). В результате вы получаете исключение "не могу выделить память". Вполне ожидаемое поведение. Обычно десятки мегабайт не грузят в память, а пользуются mapping-ом (как по русски я не знаю).
Посмотрите сюда http://labs.qt.nokia.com/2007/10/15/file-mapping/
Записан
blood_shadow
Гость
« Ответ #2 : Апрель 20, 2011, 22:25 »

На первый взгляд все нормально. Вы пытаетесь загрузить 300 мб в память(да еще и несколько таких файлов), и перекодировать в base64(на это тоже нужно место). В результате вы получаете исключение "не могу выделить память". Вполне ожидаемое поведение. Обычно десятки мегабайт не грузят в память, а пользуются mapping-ом (как по русски я не знаю).
Посмотрите сюда http://labs.qt.nokia.com/2007/10/15/file-mapping/
понял идею маппинга, но вот стало интересно почему когда у меня был один поток
при таком же занимаемом количестве памяти не вылетало исключение?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Апрель 21, 2011, 10:47 »

Не знаю подробностей задачи, поэтому рекомендации ниже "общие"

1) wait/wakeOne(All) достаточно трудно и ошибиться здесь легко, напр
Код
C++ (Qt)
 if (readFilesQueue.isEmpty())
              // <- пробой
               filesAdded.wait(&filesReadMutex);
 
это запросто может повесить задачу. Во многих случаях семафор лучше и гораздо проще для понимания

2) readAll конечно очень удобная ф-ция но так мы расписываемся что "извините, с большими файлами мы не работаем"

3) маппинг файлов - палка о 2 концах, самое неприятное что поведение может быть очень разным на разных платформах и даже версиях ОС. Всегда есть вероятность положить систему намертво, и она далеко ненулевая

4) Хорошим стилем считается обработка файла по частям неск. нитками с управляемым размером буфера
Записан
blood_shadow
Гость
« Ответ #4 : Апрель 21, 2011, 11:37 »

1) wait/wakeOne(All) достаточно трудно и ошибиться здесь легко, напр
Код
C++ (Qt)
 if (readFilesQueue.isEmpty())
           // <- proboy
          filesAdded.wait(&filesReadMutex);
 
это запросто может повесить задачу. Во многих случаях семафор лучше и гораздо проще для понимания

можете объяснить почему там пробой? я же защитил данный участок кода мьютексом:
Код
C++ (Qt)
       {
           QMutexLocker locker(&filesReadMutex);
 
           if (readFilesQueue.isEmpty())
               filesAdded.wait(&filesReadMutex);
           fileName = readFilesQueue.dequeue();
       }
 

и чем в данном случае семафор лучше мьютекса если я пытаюсь предоставлять доступ только
одному потоку?
Записан
blood_shadow
Гость
« Ответ #5 : Апрель 21, 2011, 11:40 »

4) Хорошим стилем считается обработка файла по частям неск. нитками с управляемым размером буфера
понял, вопрос - файл разбивается на части с точки зрения размера или количества ниток или же
с установленного размера буфера?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Апрель 21, 2011, 12:49 »

можете объяснить почему там пробой? я же защитил данный участок кода мьютексом:
Пусть 2 (или более) ниток стоят на wait. Хорошо, Вы положили в очередь 10 fileNames и вызвали wakeOne. Одна из ожидающих пошла молотить, а остальные? Стоят. Вроде вместо wakeOne надо wakeAll но тогда др. заморочка - а вдруг число ожидающих больше числа задач и развалимся на dequeue? Может я и неправ, но (во всяком случае для меня) это головоломка  Улыбающийся

и чем в данном случае семафор лучше мьютекса если я пытаюсь предоставлять доступ только
одному потоку?
Не лучше но куда проще. Положили 10 задач, сказали семафору release(10), а извлекающие просто вызывают acquire. Остается только защитить enqueue/dequeue мутексом

понял, вопрос - файл разбивается на части с точки зрения размера или количества ниток или же
с установленного размера буфера?
Задаем (возможно спрашивая у пользователя) общий размер используемой памяти и распределяем его между нитками. Число ниток - в большинстве случаев число ядер + 1 (главная).
Записан
blood_shadow
Гость
« Ответ #7 : Апрель 21, 2011, 14:01 »

Не лучше но куда проще. Положили 10 задач, сказали семафору release(10), а извлекающие просто вызывают acquire. Остается только защитить enqueue/dequeue мутексом
это я виноват, не указал что у меня только два потока(главный + FilesAttachementManage), проектировалось
изначально на 2 потока, потому мьютекс тут только защищает от вмешивание главного потока по добавлению
в очередь. В данном случае wakeOne(); может пробудить только вторичный поток,
использовать же wakeOne(); для пробуждения какого-нибудь из многих потоков упаси Господи Улыбающийся

Задаем (возможно спрашивая у пользователя) общий размер используемой памяти и распределяем его между нитками. Число ниток - в большинстве случаев число ядер + 1 (главная).
а если программа предназначается на общак, то есть мы число ядер будет разным,
а возможно и ОС будут разными, какими соображениями руководится?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Апрель 21, 2011, 14:31 »

это я виноват, не указал что у меня только два потока(главный + FilesAttachementManage), проектировалось
изначально на 2 потока, потому мьютекс тут только защищает от вмешивание главного потока по добавлению
в очередь. В данном случае wakeOne(); может пробудить только вторичный поток,
Пока Вы это писали, раз 5 можно было поменять на семафор и забыть о "проектировании на 2 потока"  Улыбающийся

а если программа предназначается на общак, то есть мы число ядер будет разным,
а возможно и ОС будут разными, какими соображениями руководится?
Число ядер везде известно/определяется (в Qt, насколько помню, idealThreadCount)
Записан
CL0NE
Гость
« Ответ #9 : Апрель 21, 2011, 15:50 »

Цитировать
использовать же wakeOne(); для пробуждения какого-нибудь из многих потоков упаси Господи
wake* будит только те потоки, которые на это условие ожидают.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Апрель 21, 2011, 18:10 »

Мелочь, но может пригодится: а как будете завершать рабочую нитку(и)? (есть хороший способ Улыбающийся)
Записан
blood_shadow
Гость
« Ответ #11 : Апрель 29, 2011, 17:19 »

Положили 10 задач, сказали семафору release(10), а извлекающие просто вызывают acquire. Остается только защитить enqueue/dequeue мутексом
а как создать много одинаковых потоков с общим семафором?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.142 секунд. Запросов: 22.