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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QMutex  (Прочитано 11616 раз)
niktagor
Гость
« : Сентябрь 22, 2010, 16:41 »

 В документации написано:

QMutex::Recursive In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made.

QMutex::NonRecursive In this mode, a thread may only lock a mutex once.

Если у меня один QMutex на несколько потоков, в нерекурсивном режиме каждый поток сможет сделать ему свой lock()? Есть ли какие-нибудь гарантии, что они получят к нему доступ в том порядке, в котором они этот lock() вызвали?
Записан
Авварон
Джедай : наставник для всех
*******
Online Online

Сообщений: 3258


Просмотр профиля
« Ответ #1 : Сентябрь 22, 2010, 17:22 »

мьютекс может быть заблокирован только один РАЗ (в случае рекурсивного лока, это не приведет к зависанию, если поток 1 и тот же локает несколько раз)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Сентябрь 22, 2010, 19:23 »

В документации написано:

QMutex::Recursive In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made.

QMutex::NonRecursive In this mode, a thread may only lock a mutex once.

Если у меня один QMutex на несколько потоков, в нерекурсивном режиме каждый поток сможет сделать ему свой lock()? Есть ли какие-нибудь гарантии, что они получят к нему доступ в том порядке, в котором они этот lock() вызвали?
Абсолютно никаких, порядок не определен, это "базовая" установка/понятие. Вызвавший lock позже может захватить его (а не тот кто вызвал lock раньше).

Рекурсивный мутекc - в природе его нет, это просто удобная замена такого:
Код
C++ (Qt)
static QT::HANDLE theOwner = 0;
static QMutex theMutex;
 
void DoSomethingRecursive( void )
{
// захватываем мутекс если он еще не захвачен текущей ниткой
 bool doRelease = false;
 Qt::HANDLE curID = QThread::currentThreadId();
 if (curId != theOwner) {
   theMutex.lock();
   theOwner = curId;
   doRelease = true;
 }
 
// считаем под защитой мутекса
 ...
 DoSomethingRecursive();  // возможен рекурс
 ...
 
// освобождаем для рекурсии уровня 0
 if (doRelease) {
   theOwner = 0;
   theMutex.unlock();
 }
}  
 
 
Записан
niktagor
Гость
« Ответ #3 : Сентябрь 22, 2010, 19:24 »

мьютекс может быть заблокирован только один РАЗ (в случае рекурсивного лока, это не приведет к зависанию, если поток 1 и тот же локает несколько раз)
А если разные потоки локают?
 Мне нужно, чтобы разные потоки могли читать/записывать в одну переменную. Причем каждый из них должен ждать освобождения переменной и ничего не делать в это время. Как лучше реализовать?
Записан
Kolobok
Гость
« Ответ #4 : Сентябрь 22, 2010, 19:32 »

А если разные потоки локают?
 Мне нужно, чтобы разные потоки могли читать/записывать в одну переменную. Причем каждый из них должен ждать освобождения переменной и ничего не делать в это время. Как лучше реализовать?

Использовать QMutex. Он для этого и служит.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 22, 2010, 19:35 »

А если разные потоки локают?
 Мне нужно, чтобы разные потоки могли читать/записывать в одну переменную. Причем каждый из них должен ждать освобождения переменной и ничего не делать в это время. Как лучше реализовать?
Смотря что за переменная. Если напр. надо класть/извлекать из контейнера, то просто делать это под защитой мутекса
Код
C++ (Qt)
theMutex.lock();
myList.push_back(newData);
theMutex.unlock();
 
В более сложных случаях надо заботиться о том, что прочитанные данные уже изменены
Записан
niktagor
Гость
« Ответ #6 : Сентябрь 22, 2010, 20:11 »

 В моей ситуации 10 процессов ждут доступа на чтение к одному очень большому массиву данных. А один процесс их довольно часто перезаписывает. И может возникнуть ситуация, когда пара процессов всегда будут тупо висеть в ожидании. Поэтому нужно реализовать очередность, чтобы первый вставший в очередь на считывание первым получил доступ. Как это лучше сделать?
Записан
Авварон
Джедай : наставник для всех
*******
Online Online

Сообщений: 3258


Просмотр профиля
« Ответ #7 : Сентябрь 22, 2010, 20:28 »

никак, это задача "удушения"
можно играться с приоритетом потоков, но в общем случае считается, что все потоки равноправны и кто получит доступ, неизвестно
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Сентябрь 22, 2010, 20:39 »

В моей ситуации 10 процессов ждут доступа на чтение к одному очень большому массиву данных. А один процесс их довольно часто перезаписывает. И может возникнуть ситуация, когда пара процессов всегда будут тупо висеть в ожидании. Поэтому нужно реализовать очередность, чтобы первый вставший в очередь на считывание первым получил доступ. Как это лучше сделать?
Возможно с 10 читающими всего 1 пишущему трудно будет прорваться к записи, тогда надо использовать QReadWriteLock. По поводу того что, мол, какие-то нитки будут всегда стоять: распределением нагрузки занимается OC, так что "всегда" никто стоять не будет. Может быть что одна нитка выполнит 8 задач, а другая за это же время - всего 2. Это нормально, не надо стараться сделать 5/5 - скорость будет хуже.
Записан
niktagor
Гость
« Ответ #9 : Сентябрь 22, 2010, 20:43 »

 Не может быть, чтобы не было решения. Пусть очередь будет сколь угодно большая. Нужна гарантия, что каждый поток  будет продвигаться по ней только вперед, а не назад. Пусть не с помощью мутексов.  
 Первое, что пришло в голову:
Создаем поток, занимающийся только обслуживанием очередности. У него для каждого потока есть свой отдельный мутекс. Когда он видит, что данные изменились, он разблокирует мутекс нужного потока и тот устремляется к данным. Будет работать.
 Но должно же быть красивое решение!

Цитировать
Возможно с 10 читающими всего 1 пишущему трудно будет прорваться к записи, тогда надо использовать QReadWriteLock
Так и буду делать. Но нужно еще заботиться о том, чтобы все читающие иногда получали доступ. Пусть не после каждого изменения данных, но получали.
« Последнее редактирование: Сентябрь 22, 2010, 20:49 от niktagor » Записан
Akon
Гость
« Ответ #10 : Сентябрь 22, 2010, 20:45 »

2 niktagor:

QMutex mutex;
mutex.lock();
mutex.lock();  // Error

QMutex mutex(QMutex::Recursive);
mutex.lock();
mutex.lock();  // OK

Вся разница. Нерекурсивный мьютекс это частный случай рекурсивного.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Сентябрь 22, 2010, 20:54 »

Но должно же быть красивое решение!
Улыбающийся Мне нравится Ваш подход, но решение "чего"? Как уже сказали "все нитки нагружены одинаково" = недостижимо. Тогда чего Вы хотите добиться?

Пусть очередь будет сколь угодно большая. Нужна гарантия, что каждый поток  будет продвигаться по ней только вперед, а не назад.
Ну так это и будет само собой достигаться, зачем надо прилагать еще какие-то усилия?
Записан
niktagor
Гость
« Ответ #12 : Сентябрь 22, 2010, 21:04 »

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

 Кажется, понял. Так и сделаю. Просто страшно пологаться в таком деле на Виндовс.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Сентябрь 22, 2010, 21:30 »

QMutex mutex(QMutex::Recursive);
mutex.lock();
mutex.lock();  // OK

Вся разница. Нерекурсивный мьютекс это частный случай рекурсивного.
Разница в том что второй лок просто ничего не лочит  Улыбающийся
Записан
Akon
Гость
« Ответ #14 : Сентябрь 23, 2010, 09:10 »

QMutex mutex(QMutex::Recursive);
mutex.lock();
mutex.lock();  // OK

Вся разница. Нерекурсивный мьютекс это частный случай рекурсивного.
Разница в том что второй лок просто ничего не лочит  Улыбающийся

Лочит - на каждый лок нужен анлок.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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