| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Пул объектов |
| Автор: SABROG 27.3.2010, 22:06 | ||||||||||||||||
В Qt каждый созданный QObject добавляет в конструкторе мутекс на адрес экземпляра класса в общий пул мутексов. Я нигде не нашел, чтобы мутекс удалялся, даже когда память под объект уже давно освобождена. Пул мутексов мочится целиком только когда последний QObject в программе уничтожен. Заинтересовала эта строчка формирования индекса:
Если предположить, что объекты размеров в байт будут располагаться по адресам 100,101,102:
То на все эти адреса будет один и тот же мутекс? Теперь увеличим дистанцию на 32 бита, возможно мутексы не умеют работать с данными меньше 4х байт:
Тут каждый объект получил по своему личному мутексу. А теперь увеличим размер указателя до 8 байт (вообще указатель void* может иметь разные размеры на одной и той же машине?):
То есть на 2 объекта по 1 общему мутексу. Я чего-то не понимаю или залочка одного мутекса для одного объекта может блокировать работу другого объекта? Что если объекты находятся вообще в разных потоках и работают асинхронно? Ну и соответственно если я создам пару миллионов объектов, то из-за операции взятия остатка на многие из них будут снова общие мутексы. Означает ли это, что каждый раз, когда я в слоте пытаюсь узнать кто послал сигнал через метод sender():
То вот этот "друг"
Может заблокировать параллельно еще какой-нибудь случайный QObject, например QTcpSocket, который пытается принять в отдельном потоке клиента? Потому, что:
Может получить общий мутекс? Или у меня с математикой что-то плохо? |
| Автор: borisbn 28.3.2010, 22:31 |
| а точно signalSlotMutexes является QMutexPool * ? может быть не является вызовом |
| Автор: SABROG 28.3.2010, 22:45 | ||
Он так объявлен в qobject.cpp:
То есть это своего рода "умный указатель" QBasicAtomicPointer. |
| Автор: borisbn 28.3.2010, 22:57 |
| SABROG, да, уже посмотрел. получается, что действительно вызов sender() может заблокировать вызов sender() из другого объекта. заметь, блокируется не объект, а вызов sender(), и не более того P.S. Может стоит перенести тему в "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets" ? |
| Автор: borisbn 28.3.2010, 23:59 | ||||||
по-моему, это обычный hash (кстати, в более ранней версии Qt использовался как раз QHash, а не остаток от деления) ну, а если быть совсем точным, то
верно для 64-х битных указателей, т.к. для 32-х разрядной ОС sizeof(address) >> 1 = 2, т.е. должно быть
|
| Автор: SABROG 29.3.2010, 00:13 | ||||||||
Обрати внимание, там сдвиг идет в 2 этапа:
4 >> 1 эквивалентно: 4/2 = 2 Потом второй этап:
То есть смещение уже зависит от размера указателя. А смещение на 2 эквивалентно делению на 4. Вот таблица, чтобы понятней было:
Отсчет ведется с 1 до 10. Первая цифра смещение на 1 == делению на 2, смещение на 2 == делению на 4 и так далее. В QHash не обнаружил подобного кода. --- Сейчас погуглил, наткнулся на такой код:
То есть правда в твоих словах есть. Остается понять откуда взялась вторая часть и почему хеш получается не уникальным. --- При беглом прочтении нескольких статей про хэши сделал вывод, что коллизия обычное дело. Если она возникает, то обычно сравниваются уже значения, если они разные, то происходит rehash. В случае с Qt слежения за коллизиями я не увидел, так как сами адреса нигде не хранятся, вместо них хранятся данные, которые никак к адресам не привязаны. Воозможно еще проблема в том, что я взал маленькие значения адресов, может быть при каких-нибудь 0x00410000h я буду уже не так часто получать коллизии? |
| Автор: borisbn 29.3.2010, 07:06 |
| SABROG, 1. Про сдвиг значения указателя на 2 -я протупил 2. В старом, ещё trolltech'вском коде mutex получался через QHash от указателя 3. Значение самого указателя (100 или 410000h) не играет роли, т.к. они берут остаток от деления на количество mutex'ов. Слежения за коллизиями я тоже не увидел, значит получается, что все функции, использующие QMutexPool могут блокировать друг друга |
| Автор: SABROG 29.3.2010, 08:51 |
| Написал троллям, посмотрим чего они скажут. |
| Автор: SABROG 29.3.2010, 14:46 | ||||
Thiago Maciera написал такой ответ и пометил багрепорт как invalid:
Говорит, что размер объекта почти никогда не бывает 1 байт и обычно составляет несколько размеров указателя void*. Раз несколько, то минимум 8 байт (по 4 байта на указатель). Но я оставил коммент, что даже в этом случае коллизии есть. ---
Хотят компилируемый пример с тормозами --- Кому интересно, за перепиской с троллями можно наблюдать http://bugreports.qt.nokia.com/browse/QTBUG-9461. Выяснилась еще одна особенность. Максимальное количество мутексов - 131. Если при этом в программе 10 тысяч объектов, то на каждый мутекс может приходится 70-80 объектов. При 200 объектах это значение не так великов 1-5, но факт остается фактом, а возможность коллизии довольно большая. P.S.: математический вопрос считаю решенным, тема перетекла в русло Qt, можно переместить в соответствующий раздел. Спасибо borisbn за подсказку с хэшами, плюс один. |
| Автор: borisbn 30.3.2010, 10:07 | ||
хитрые тролли ---------------------------------------- Vladislav, прочитал переписку. IMHO - очень дельное предложение сделать отдельный QMutexPool для каждого потока. Буду следить за войной русского программиста с финскими кодерами |