Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Пул объектов, не пойму, как Qt вычисляет индекс 
V
    Опции темы
SABROG
  Дата 27.3.2010, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Код

/*!
    Returns a QMutex from the pool. QMutexPool uses the value \a address
    to determine which mutex is returned from the pool.
*/
QMutex *QMutexPool::get(const void *address)
{
    Q_ASSERT_X(address != 0, "QMutexPool::get()", "'address' argument cannot be zero");
    int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count());

    if (!mutexes[index]) {
        // mutex not created, create one
        QMutex *newMutex = new QMutex(recursionMode);
        if (!mutexes[index].testAndSetOrdered(0, newMutex))
            delete newMutex;
    }

    return mutexes[index];



В Qt каждый созданный QObject добавляет в конструкторе мутекс на адрес экземпляра класса в общий пул мутексов. Я нигде не нашел, чтобы мутекс удалялся, даже когда память под объект уже давно освобождена. Пул мутексов мочится целиком только когда последний QObject в программе уничтожен.

Заинтересовала эта строчка формирования индекса:

Код

    int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count());


Если предположить, что объекты размеров в байт будут располагаться по адресам 100,101,102:

Код

100 = 100 / 4 = 25 % 3 = 1
101 = 101 / 4 = 25 % 3 = 1
102 = 102 / 4 = 25 % 3 = 1


То на все эти адреса будет один и тот же мутекс? Теперь увеличим дистанцию на 32 бита, возможно мутексы не умеют работать с данными меньше 4х байт:
Код

100 = 100 / 4 = 25 % 3 = 1
104 = 104 / 4 = 26 % 3 = 2
108 = 108 / 4 = 27 % 3 = 0


Тут каждый объект получил по своему личному мутексу. А теперь увеличим размер указателя до 8 байт (вообще указатель void* может иметь разные размеры на одной и той же машине?):

Код

100 = 100 / 16 = 6 % 3 = 0
108 = 108 / 16 = 6 % 3 = 0
116 = 116 / 16 = 7 % 3 = 1
124 = 124 / 16 = 7 % 3 = 1


То есть на 2 объекта по 1 общему мутексу. Я чего-то не понимаю или залочка одного мутекса для одного объекта может блокировать работу другого объекта? Что если объекты находятся вообще в разных потоках и работают асинхронно? Ну и соответственно если я создам пару миллионов объектов, то из-за операции взятия остатка на многие из них будут снова общие мутексы.

Означает ли это, что каждый раз, когда я в слоте пытаюсь узнать кто послал сигнал через метод sender():

Код

QObject *QObject::sender() const
{
    Q_D(const QObject);

    QMutexLocker locker(signalSlotLock(this));
    if (!d->currentSender)
        return 0;

    // Return 0 if d->currentSender isn't in d->senders
    bool found = false;
    for (QObjectPrivate::Connection *c = d->senders; c && !found; c = c->next)
        found = (c->sender == d->currentSender->sender);
    if (!found)
        return 0;
    return d->currentSender->sender;



То вот этот "друг"

Код

QMutexLocker locker(signalSlotLock(this));


Может заблокировать параллельно еще какой-нибудь случайный QObject, например QTcpSocket, который пытается принять в отдельном потоке клиента? Потому, что:

Код

static QMutex *signalSlotLock(const QObject *o)
{
    if (!signalSlotMutexes) {
        QMutexPool *mp = new QMutexPool;
        if (!signalSlotMutexes.testAndSetOrdered(0, mp)) {
            delete mp;
        }
    }
    return signalSlotMutexes->get(o);



Может получить общий мутекс? Или у меня с математикой что-то плохо?


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
borisbn
Дата 28.3.2010, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



а точно signalSlotMutexes является QMutexPool * ?

может быть
Цитата(SABROG @  27.3.2010,  22:06 Найти цитируемый пост)

Код

return signalSlotMutexes->get(o);


не является вызовом 
Цитата(SABROG @  27.3.2010,  22:06 Найти цитируемый пост)

Код

QMutex *QMutexPool::get(const void *address)





--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SABROG
Дата 28.3.2010, 22:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Цитата(borisbn @  28.3.2010,  22:31 Найти цитируемый пост)
а точно signalSlotMutexes является QMutexPool * ?

Он так объявлен в qobject.cpp:

Код

static QBasicAtomicPointer<QMutexPool> signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0);


То есть это своего рода "умный указатель" QBasicAtomicPointer.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
borisbn
Дата 28.3.2010, 22:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



SABROG, да, уже посмотрел. получается, что действительно вызов sender() может заблокировать вызов sender() из другого объекта. заметь, блокируется не объект, а вызов sender(), и не более того

P.S. Может стоит перенести тему в "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets" ?

Это сообщение отредактировал(а) borisbn - 28.3.2010, 23:03


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SABROG
Дата 28.3.2010, 23:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Цитата(borisbn @  28.3.2010,  22:57 Найти цитируемый пост)
может заблокировать вызов sender()

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

Цитата(borisbn @  28.3.2010,  22:57 Найти цитируемый пост)
Может стоит перенести тему в "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"

Речь не совсем о Qt, меня интересует верность рассчетов индекса от адреса объекта. Задача скорее математическая. Либо я чего-то не правильно посчитал, либо это так и есть. Может быть просто кто-то видел подобный алгоритм поиска объекта в массиве по адресу объекта в других проектах?

Это сообщение отредактировал(а) SABROG - 28.3.2010, 23:34


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
borisbn
Дата 28.3.2010, 23:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(SABROG @  28.3.2010,  23:32 Найти цитируемый пост)
Может быть просто кто-то видел подобный алгоритм поиска объекта в массиве по адресу объекта в других проектах

по-моему, это обычный hash (кстати, в более ранней версии Qt использовался как раз QHash, а не остаток от деления)
ну, а если быть совсем точным, то
Код

100 = 100 / 4 = 25 % 3 = 1
101 = 101 / 4 = 25 % 3 = 1
102 = 102 / 4 = 25 % 3 = 1

верно для 64-х битных указателей, т.к. для 32-х разрядной ОС
sizeof(address)  >> 1 = 2, т.е. должно быть
Код

100 = 100 / 2 = 50 % 3 = 2
101 = 101 / 2 = 50 % 3 = 2
102 = 102 / 2 = 50 % 3 = 2







--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SABROG
Дата 29.3.2010, 00:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Цитата(borisbn @  28.3.2010,  23:59 Найти цитируемый пост)
т.е. должно быть

Обрати внимание, там сдвиг идет в 2 этапа:

Код

sizeof(address) >> 1


4 >> 1 эквивалентно: 4/2 = 2

Потом второй этап:

Код

quintptr(address) >> 2


То есть смещение уже зависит от размера указателя. А смещение на 2 эквивалентно делению на 4.

Вот таблица, чтобы понятней было:

Код

2,4,8,16,32,64,128,256,512,1024


Отсчет ведется с 1 до 10. Первая цифра смещение на 1 == делению на 2, смещение на 2 == делению на 4 и так далее.

В QHash не обнаружил подобного кода.
---
Сейчас погуглил, наткнулся на такой код:

Код

    virtual U_32 getKeyHashCode(void* key) const {
        // return hash of address bits
        return ((U_32)(((POINTER_SIZE_INT)key) >> sizeof(void*)));
    }


То есть правда в твоих словах есть. Остается понять откуда взялась вторая часть и почему хеш получается не уникальным.
---
При беглом прочтении нескольких статей про хэши сделал вывод, что коллизия обычное дело. Если она возникает, то обычно сравниваются уже значения, если они разные, то происходит rehash. В случае с Qt слежения за коллизиями я не увидел, так как сами адреса нигде не хранятся, вместо них хранятся данные, которые никак к адресам не привязаны. Воозможно еще проблема в том, что я взал маленькие значения адресов, может быть при каких-нибудь 0x00410000h я буду уже не так часто получать коллизии?

Это сообщение отредактировал(а) SABROG - 29.3.2010, 00:42


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
borisbn
Дата 29.3.2010, 07:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



SABROG
1. Про сдвиг значения указателя на 2 -я протупил
2. В старом, ещё trolltech'вском коде mutex получался через QHash от указателя
3. Значение самого указателя (100 или 410000h) не играет роли, т.к. они берут остаток от деления на количество mutex'ов.
Слежения за коллизиями я тоже не увидел, значит получается, что все функции, использующие QMutexPool могут блокировать друг друга


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
SABROG
Дата 29.3.2010, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Написал троллям, посмотрим чего они скажут.


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
SABROG
Дата 29.3.2010, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 4
Всего: 91



Thiago Maciera написал такой ответ и пометил багрепорт как invalid:

Цитата

The sizeof such objects is almost never 1. It's usually a multiple of sizeof(void*).


Говорит, что размер объекта почти никогда не бывает 1 байт и обычно составляет несколько размеров указателя void*. Раз несколько, то минимум 8 байт (по 4 байта на указатель). Но я оставил коммент, что даже в этом случае коллизии есть.
---
Цитата

Remember that object addresses will be kind of randomized by the allocator.
specially if they are living in different threads, there is very small likelyhood that the objects will have addresses that are that close anyway.

If you can provide a compilable testcase that shows any performance penalty because of those locks, you are welcome.

Notice that at least QObject::receivers and QObject::dumpObjectInfo() are not optimized for speed as they are debugging functions.


Хотят компилируемый пример с тормозами  smile То есть тот факт, что подобная проблема может выскочить их не волнует.
---
Кому интересно, за перепиской с троллями можно наблюдать тут.

Выяснилась еще одна особенность. Максимальное количество мутексов - 131. Если при этом в программе 10 тысяч объектов, то на каждый мутекс может приходится 70-80 объектов. При 200 объектах это значение не так великов 1-5, но факт остается фактом, а возможность коллизии довольно большая.

P.S.: математический вопрос считаю решенным, тема перетекла в русло Qt, можно переместить в соответствующий раздел. Спасибо borisbn за подсказку с хэшами, плюс один.

Это сообщение отредактировал(а) SABROG - 29.3.2010, 21:55


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
borisbn
Дата 30.3.2010, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(SABROG @  29.3.2010,  14:46 Найти цитируемый пост)
If you can provide a compilable testcase that shows any performance penalty because of those locks, you are welcome

хитрые тролли  smile . Ведь может быть так, что у тебя или у меня на компьютере проблема возникнет, а у них - нет, потому что память разляжется по-другому и указатели не пересекутся
----------------------------------------
Vladislav, прочитал переписку. IMHO - очень дельное предложение сделать отдельный QMutexPool для каждого потока.
Буду следить за войной русского программиста с финскими кодерами smile

Это сообщение отредактировал(а) borisbn - 30.3.2010, 10:18


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1296 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.