Russian Qt Forum
Ноябрь 25, 2024, 06:50 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Создание очереди запросов  (Прочитано 7076 раз)
virtual_root
Гость
« : Август 20, 2012, 11:31 »

Добрый день. Ребята, у меня возник вопрос, подскажите решение!
У меня есть БД, к которой из разных потоков могут обращаться классы и записывать, удалять и прочие функции выполнять с данными.
При множественной работе с БД, чтобы не возникло конфликтов, я так понимаю мне нужно использовать мьютексы и на время выполнения запроса блокировать БД, чтобы другой поток не мог ничего изменить во время выполнения запросов.
Я хочу создать какую-нибудь очередь запросов и выполнять их. Т.е. есть класс А работающий в потоке А и есть класс В работающий в потоке В. Они одновременно хотят выполнить разные запросы к БД, вызвав фунции InsertData() и DeleteData() из класса DataBase. Как мне сделать такую очередь чтобы в ней можно было в ней хранить вызовы функ-й InsertData() и DeleteData() и других от разных классов и по очереди выполнять эту функцию с разными запросами.
Это что-то вроде тех же сигналов и слотов, только как мне их так прикрутить к моей задаче?
Подскажите пожалуйста!)
« Последнее редактирование: Август 20, 2012, 11:34 от tiny developer » Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #1 : Август 20, 2012, 11:51 »

Дык сигналами и слотами и прикручивай.
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Август 20, 2012, 12:39 »

Сигналы с типом коннекта QururdConnection и есть очередь (событий). Поручаете одной нитке обращаться к базе, а все остальные шлют ей такие сигналы - вот и все. Также нужно поинтересоваться - если Ваша СУБД multi-threaded то необходимости в этом нет
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #3 : Август 20, 2012, 15:46 »

Речь идёт о многопользовательском доступе к СУБД или к её модели в Qt? Если о БД - то проблема должна решаться на её уровне (блокировки записей, страниц и т.п.). Иначе при работе, например, двух клиентских приложений одновременно - ничем тебя ни мьютексы, ни сигнал/слоты не спасут.
« Последнее редактирование: Август 20, 2012, 20:23 от xokc » Записан
virtual_root
Гость
« Ответ #4 : Август 21, 2012, 10:21 »

речь идет о модели. Т.е. у меня есть классы внутри одного приложения которые могут одновременно выполнять такие операции к бд как insert, update, delete. Насколько я знаю, то можно только один из такого рода запросов выполнить в единицу времени. А вот запросы select могут и параллельно обращаться. Получается что читать базу могут одновременно несколько потоков, а писать должен только один. И мне бы хотелось ни сигналы слать, чтобы добавить данные(я же как0то и данные должна передавать), а вызывать функцию которая выполняет запрос на добавление, но её вызовы, если их несколько одновременно - ложить в очередь и из неё выполнять, при этом возвращая результат вызвывшему классу или его методу.
Записан
virtual_root
Гость
« Ответ #5 : Август 21, 2012, 10:29 »

Класс который работает напрямую с бд и выполняет запросы у меня сиглтон.
Записан
virtual_root
Гость
« Ответ #6 : Август 21, 2012, 10:37 »

Как бы я хочу сделать так: если вызвана одна из трех функций:
Код
C++ (Qt)
 virtual DataBaseError UpdateData(QString TableName,QHash<QString, QVariant> data, QString condition);  // обновление одной записи
   virtual DataBaseError InsertData(QString TableName,QHash<QString, QVariant> data);  // добавление  записи
   virtual DataBaseError Delete(QString TableName, QString condition);
то полодить её вызов в очередь. А какая-нибудь внутренняя функция класса проверяет всё время очередь и если появились вызовы функций, то немедленно их поочереди исполняет. После исполнения эта функция должна вернуть результат, той функции которая запросила вызов одной из терх вышеуказанных функций. Т.о. получается функция X()  вызвала фун-ю InsertData(QString TableName,QHash<QString, QVariant> data); Вызов этой функции попал в очередь. А функция X() ждет пока вернется результат выполнения вызвынной функции.
Как мне заставить функцию ждать результат выполнения? И как положить вызовы в очередь? Что использовать в качестве очереди?
Записан
virtual_root
Гость
« Ответ #7 : Август 21, 2012, 11:11 »

я придумала как поступить для 3-х функций:
Код
C++ (Qt)
virtual DataBaseError UpdateData(QString TableName,QHash<QString, QVariant> data, QString condition);  // обновление одной записи
   virtual DataBaseError InsertData(QString TableName,QHash<QString, QVariant> data);  // добавление сразу нескольких запесей
   virtual DataBaseError Delete(QString TableName, QString condition);
они просто будут посылать сигнал с параметром функции ExecQuery(QString). В качетве параметра будут передавать запрос.
Поскольку запросы типа insert, update и delete не требуют возвращающего значения(набора записей) то такой вариант мне подходит. Но как быть с запросами select ведь мне нужно дождаться возвращающего занчения изтой функции которая вышлет сигнал. Как такое сделать?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Август 21, 2012, 11:58 »

Поскольку запросы типа insert, update и delete не требуют возвращающего значения(набора записей) то такой вариант мне подходит. Но как быть с запросами select ведь мне нужно дождаться возвращающего занчения изтой функции которая вышлет сигнал. Как такое сделать?
Можно создать свою очередь напр используя QList. Но неясно чего Вы хотите, ведь полученные результаты select могут уже ничему не соответствовать  если потом было insert/delete. Это нужно решать на уровне посылающих, т.е. не обновлять базу пока чтение не закончено, возможно используя QReadWriteLock
Записан
trot
Гость
« Ответ #9 : Август 21, 2012, 13:22 »

Можно поинтересоваться, что у вас за приложение, кто или что будет вызывать запросы в базу данных. Зачем нужна необходимость выполнять запросы в отдельных потоках. Эти потоки замыкаются на отдельное соединение с БД или вы еще для каждого потока создаете свое соединение с БД.
Записан
virtual_root
Гость
« Ответ #10 : Август 22, 2012, 10:59 »

Я пишу класс который будет использоваться в приложении во многих других классах и они в свою очередь будут через него выполнять запросы к бд. Некоторые из классов которые будут работать с моим классом( а мне не известно какие, просто дали задачу разработать определенный класс) будут работать в отдельных потоках.
У меня ещё пару вопросов появилось:
а можно сделать несколько соединений с одной и той же БД ? Как?
еще раз вызвать метод QSqlDatabase::open() ?
И как можно сделать сигнал приватным? Чтобы его мог использовать только сам класс. Это мне для очереди надо)
Ребят, подскажите пожалуйста.
Записан
virtual_root
Гость
« Ответ #11 : Август 22, 2012, 11:25 »

Ребята, я правильно понимаю: если у меня один и тот же сигнал просигналил в разных потоках одновременно, то слот на него подписанный исполнится поочередно? Т.е. сначала обработает один сигнал, а потом другой? Не сразу в двух потока, произойдет исполнение слота?
соединяю так:
Код:
connect(this,SIGNAL(_execQuery(QString)),this,SLOT(ExecQuery(QString)),Qt::QueuedConnection);

Ведь по логики слот обрабатывается в том потоке в котором был издан сигнал. А у меня предположим сигнал был издан в двух потоках, то как тогда поведет себя слот?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Август 22, 2012, 11:32 »

Ребята, я правильно понимаю: если у меня один и тот же сигнал просигналил в разных потоках одновременно, то слот на него подписанный исполнится поочередно? Т.е. сначала обработает один сигнал, а потом другой? Не сразу в двух потока, произойдет исполнение слота?
соединяю так:
Код:
connect(this,SIGNAL(_execQuery(QString)),this,SLOT(ExecQuery(QString)),Qt::QueuedConnection);

Ведь по логики слот обрабатывается в том потоке в котором был издан сигнал. А у меня предположим сигнал был издан в двух потоках, то как тогда поведет себя слот?
Нет, смысл QueuedConnection в том что слот будет вызван в той нитке где он живет (по умолчанию - где был создан, можно установить с помощью moveToThread). Поэтому порядок срабатывания слотов может быть любым и меняться от одного выполнения до другого.
Записан
virtual_root
Гость
« Ответ #13 : Август 22, 2012, 11:45 »

Тогда в моей ситуации это поможет?
Код
C++ (Qt)
void PQInterfaceFunctionPostgreSQL::ExecQuery(QString str){
 
   str.left(str.indexOf(';'));   // для обеспечения безопасности обрежим строку до символа ;
 
   if (!_db.isOpen()) emit Error(DataBaseNoOpen);
   else {
       QMutexLocker lock(_mutex);   // мы блокируем кусок кода поле этой строки пока объект lock не будет уничтожен
       QSqlQuery query(_db);
       if (!query.exec(str)) emit Error(SQLEror);
   }
 
}

Тогда получается мне всё равно где слот исполняется, так как запросы к бд выполнятся всё равно по очереди, так?
 ну т.е. вызвался слот, смотрит а там заблокоровано и он будет ждать разблокировки а потом исполняться?
« Последнее редактирование: Август 22, 2012, 11:47 от tiny developer » Записан
virtual_root
Гость
« Ответ #14 : Август 22, 2012, 11:47 »

или мне нужно что-то дописать чтобы параллельно вызванный слот дождался разблокировки а потом выполнился? И если я изменю слот на обычную функцию, что надо дописать чтобы она дождалась разблокировки мьютекса и продолжила своё выполнение?
« Последнее редактирование: Август 22, 2012, 11:50 от tiny developer » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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