Russian Qt Forum

Qt => Общие вопросы => Тема начата: kuzulis от Январь 27, 2009, 16:07



Название: Объясните идею Mutex :)
Отправлено: kuzulis от Январь 27, 2009, 16:07
Доброго времени суток!

имеется класс:
Код:
class MyClass
{
public:
   int getValue();
   void setValue(int value);
private:
   int val;
.......
}

Код:
int MyClass::getValue
{
   //QMutexLocker locker(&mutexValue) - нужно ли????
   return val;
}

void MyClass::setValue(int value)
{
   //QMutexLocker locker(&mutexValue) - нужно ли????
   val = value;
}

нужно ли в данном случае защищать переменную val мьютексами ???
при условии что где-то в приложении очень активно и часто вызываются ф-ции getValue и setValue (например их разные потоки вызывают и т.п) и необходимо писать/читать переменную по возможности как можно быстрее

я это спросил к тому - например мне в принципе не важно успеет прочитаться предыдущ значение переменной val до ее изменения или нет!!!
т.е пусть другие потоки меняют когда и как хотят эту переменную - мне не важно!

т.е какой-то поток постоянно обновляет данные , вызывая setValue , а другой поток постоянно читает getValue

или я шо-то не пойму! :)

 


Название: Re: Объясните идею Mutex :)
Отправлено: Laex от Январь 27, 2009, 16:51
Конкретно в твоём случае мутекс не нужен, т.к. данные типа int и их нельзя прочитать на половину. Вот если бы у тебя был QString вместо int то мутекс бы тебе был необходим т.к. поток может быть прерван "посередине" записи. Например:
Поток 1:
str = "Begin 1 string bla-bla end 1 string"
Поток 2 пытается писать:
str = "Begin 2 string bla-bla end 2 string"
но прерван "посередине" записи потоком 1, который читает из str.
В результате поток 1 получит
"Begin 2 string bla-bla end 1 string"

Только в том случае, когда поток может быть прерван "посередине" операции, которая должна быть атомарной, другим потоком использующем те же данные надо использовать мутексы.


Название: Re: Объясните идею Mutex :)
Отправлено: pastor от Январь 27, 2009, 17:37
Mutex нужен, т.к. присваивание это не атомарная операция


Название: Re: Объясните идею Mutex :)
Отправлено: Laex от Январь 27, 2009, 17:55
Присваивание int атомарная операция т.к. в конце всё сводится к чтото типа:
Код:
mov [data_ptr],eax
Всё что было до этого(вычисление адреса и т.д.) не влияет на данные.


Название: Re: Объясните идею Mutex :)
Отправлено: pastor от Январь 27, 2009, 18:57
Всё что было до этого(вычисление адреса и т.д.) не влияет на данные.

Это интересно. Я у меня другая информация, что это есть частный случай и платформозависим. Именно поэтому в Qt имеется класс QAtomicInt (http://doc.trolltech.com/4.4-snapshot/qatomicint.html).


Название: Re: Объясните идею Mutex :)
Отправлено: Dendy от Январь 27, 2009, 19:39
Конкретно в твоём случае мутекс не нужен, т.к. данные типа int и их нельзя прочитать на половину. Вот если бы у тебя был QString вместо int то мутекс бы тебе был необходим т.к. поток может быть прерван "посередине" записи.

Всё с точностью до наоборот. Присваивание int может быть неатомарно на разных платформах. Как сказал Павел - для этого в Qt ввели класс QAtomicInt.
Изменение же QString - операция атомарная, так как он построен по принципу Copy On Write, причём разделение данных сделано атомарными операциями.

Вам и топикстартеру:
http://doc.trolltech.com/4.4/atomic-operations.html
http://doc.trolltech.com/4.4/shared.html
http://doc.trolltech.com/4.4/explicitly-shared.html


Название: Re: Объясните идею Mutex :)
Отправлено: lit-uriy от Январь 27, 2009, 21:04
от туда же:
QString, All the functions in this class are reentrant, ....


Название: Re: Объясните идею Mutex :)
Отправлено: Dendy от Январь 27, 2009, 21:14
от туда же:
QString, All the functions in this class are reentrant, ....

Голый int тоже reentrant. Автор спрашивал про thread-safe.


Название: Re: Объясните идею Mutex :)
Отправлено: kuzulis от Январь 28, 2009, 08:32
1. а если переменная VAL имеет тип QVariant или является какой нить структурой?

2. если я введу мьютекс, то на сколько примерно упадет скорость работы с этой переменной? как это можно оценить?

3. сколько вносят задержки сам вызов и выполнение функций getValue и setValue (примерно), ведь можно чтобы уменьшить время обработки - просто объявить эту переменную как Public (теоретически) :)


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



Название: Re: Объясните идею Mutex :)
Отправлено: Dendy от Январь 28, 2009, 11:02
1. Нужно смотреть какой тип переменой в каждом случае. Даже с простыми типами код нужно делать потокобезопастным. Кстати, интересный вопрос по QVariant, ни в документации, ни судя по коду он НЕ потокобезопастный, поправьте если я неправ.

2. Пишите простой цикл и меряете сколько выполняется миллион итераций с мутексами и без.

3. Если методы inline - тогда никакой разницы. Вообще нужно смотреть по ситуации, смотря какая задача.

Если у вас более одной переменной в структуре типа - тоже нужно добавлять потокобезопастность. Варианты:
1. С помощью мутексов.
2. Обьединить данные в структуру и засунуть её в QSharedDataPointer. Данные будут выделяться в памяти и происходить лишнее разименование, зато будут отсутствовать мутексы, а следовательно и накладные расходы с ними связанные.


Название: Re: Объясните идею Mutex :)
Отправлено: kuzulis от Январь 28, 2009, 13:52
Спасибо большое! :)


Название: Re: Объясните идею Mutex :)
Отправлено: Swappp от Январь 28, 2009, 20:42
А у меня такой вопрос по поводу потокобезопасности int:
Есть приложение, главный поток занимается отрисовкой GUI как и положено. Создается второй поток, который производит некоторые вычисления. В главном потоке несколько раз в секунду производится чтение и отрисовка значения из int, которое в этот же момент может изменятся во втором потоке. Корректность отрисовываемых данных не критична. Т.е. ничего страшного, если там будет нарисовано какое-то не то значение, т.к. все равно если значение часто меняется (частота перерисовки превышает 25 кадров в сек.), его и так не возможно точно прочитать, главное видеть меняется ли оно и возможно примерно определять старшие разряды. Так вот, могут ли на разнообразных платформах в принципе возникнуть какие-нибудь другие проблемы, кроме отрисовки некорректных данных?


Название: Re: Объясните идею Mutex :)
Отправлено: serg_hd от Май 13, 2010, 17:09
А нужен ли QMutex для метода, в котором происходит только чтение (напр. контейнера) без изменения его содержимого? К этому методу обращается множество потоков. По-идее не нужен ведь?


Название: Re: Объясните идею Mutex :)
Отправлено: ритт от Май 13, 2010, 18:40
если этот контейнер после старта данных потоков(а) никем и никогда не изменяется, защищать не нужно.


Название: Re: Объясните идею Mutex :)
Отправлено: spectre71 от Май 13, 2010, 19:33
если этот контейнер после старта данных потоков(а) никем и никогда не изменяется, защищать не нужно.

И если при чтении данных из контейнера не изменяются никакие его внутренние переменные/поля/глобалы (что вполне возможно, и зависит от реализации конкретного контейнера)


Название: Re: Объясните идею Mutex :)
Отправлено: SimpleSunny от Май 13, 2010, 20:15
Можно также посоветовать QReadWriteLock, если читать переменную будут несколько потоков, а запись производится редко.


Название: Re: Объясните идею Mutex :)
Отправлено: serg_hd от Май 13, 2010, 21:15
если этот контейнер после старта данных потоков(а) никем и никогда не изменяется, защищать не нужно.

И если при чтении данных из контейнера не изменяются никакие его внутренние переменные/поля/глобалы (что вполне возможно, и зависит от реализации конкретного контейнера)
Речь идёт о QList<QPair<QString, QString>>. Думаю, с ним проблем не будет.

Можно также посоветовать QReadWriteLock, если читать переменную будут несколько потоков, а запись производиться редко.
не знал о нём, спасибо, попробуемс


Название: Re: Объясните идею Mutex :)
Отправлено: spectre71 от Май 14, 2010, 07:48
Речь идёт о QList<QPair<QString, QString>>. Думаю, с ним проблем не будет.

Читаем доку.

Цитировать
QList Class Reference
Note: All functions in this class are reentrant.

Цитировать
A thread-safe function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.
A reentrant function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.

Цитировать
By extension, a class is said to be reentrant if its member functions can be called safely from multiple threads, as long as each thread uses a different instance of the class. The class is thread-safe if its member functions can be called safely from multiple threads, even if all the threads use the same instance of the class.

Нет никакой гарантии что методы чтения данных QList потокобезопасны сейчас(что можно проверить посмотрев сорцы) или будут таковыми в следующих версиях. Так что защищать надо в любом случае.


Название: Re: Объясните идею Mutex :)
Отправлено: Akon от Октябрь 01, 2010, 11:24
Mutex нужен, т.к. присваивание это не атомарная операция

Присваивание будет неатомарным, если для него генерируется >1 машинной инструкции, исключая загрузку адресов. Например, для 32-разрядного типа на 16-разрядной платформе будет две машинные инструкции пересылки данных.

QAtomicInt нужен для несколько больших чем обычное присваивание действий. Непосредственно присваивание - это только часть атомарной операции.

По коду в топике - если sizeof(int) <= sizeof(machine_word) (т.е. 1 машинная инструкция на установку), то переменная должна быть volatile, синхронизация ни в каком виде не нужна.


Название: Re: Объясните идею Mutex :)
Отправлено: Igors от Октябрь 01, 2010, 12:58
я это спросил к тому - например мне в принципе не важно успеет прочитаться предыдущ значение переменной val до ее изменения или нет!!!
Довольно фантастическая ситуация (если "неважно"). Ну тогда чтение защищать не нужно (не будем притворяться что поддерживаем 16-бит платформы  :)). А запись все равно надо.  

1. а если переменная VAL имеет тип QVariant или является какой нить структурой?

2. если я введу мьютекс, то на сколько примерно упадет скорость работы с этой переменной? как это можно оценить?

3. сколько вносят задержки сам вызов и выполнение функций getValue и setValue (примерно), ведь можно чтобы уменьшить время обработки - просто объявить эту переменную как Public (теоретически) :)
В лучшем случае - доли процента. В худшем - раз в 10. Все зависит от того насколько интенсивна "конкуренция за ресурс". Если реально нужна скорость - выкидывайте мутексы и переходите на атомарные локи