Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > использование bool в многопоточном приложении


Автор: georain 10.6.2008, 23:49
В многопоточном приложении есть переменная состояния bool с блокировками при её установке и чтении, например так:
Код

    bool a;

Код

lock()
    bool = true;
unlock()

Код

lock()
    bool b = a;
unlock()
    if(b){...};

Будет ли что-то страшное если убрать блокировку?
Честно говоря я не вижу смысла её тут ставить.

P.S. Поделитесь опытом работы с bool типами в многопоточности. Тут вроде не происходит чтения перед записью, только запись, а запись происходит как бы одной операцией, что может поломаться то (если рядом с установкой/чтением больше ничего нет), зачем блокировать?

Автор: andrew_121 10.6.2008, 23:56
bool не чем не отличаеться от обычных переменных типа int, кроме того что принимает только два значения - true, false.
Если к переменной, доступ получают несколько потоков, тогда блокировка необходима.

Автор: georain 11.6.2008, 00:04
Цитата(andrew_121 @  10.6.2008,  23:56 Найти цитируемый пост)
Если к переменной, доступ получают несколько потоков, тогда блокировка необходима. 

Это я уже слышал, меня интересует почему? Что случится если блокировки не будет? (только применительно к bool)

Моё понимание что происходит с int:
В одно и тоже время один поток хочет увеличить int на 5, другой тоже хочет увеличить int на 10.
С блокировкой: они последовательно увеличивают int (пока один делает операции, второй ожидает), в итоге int увеличивается на 15.
Без блокировки: первый поток читает int из памяти и заносит в регистр ЦП, второй делает тоже самое, первый поток увеличивает это значение на 5 (в регистре ЦП), второй делает тоже самое на 10, первый поток записывает int в память, второй делает тоже самое, в итоге в памяти оказывается значение одного из двух регистров. Мало того что int увеличился не на 15 а на 10 или 5, непонятно на 5 или на 10 он увеличился smile
А с bool то что будет?

Автор: andrew_121 11.6.2008, 00:56
boob - принимает только два значения - true, false.
Допустим, один поток хочет получить значение переменной, а другой, в это же время, изменить. Что произойдет без блокировки? Секёшь?

Примерчик:
Код

void LTimer::set_millisecond( luint32 p ) {
    LMutex mutex; // Мьютекс
    LMutexLock locker( &mutex ); // Локер
    _interval = p;
}
//---------------------------------------------------------------------------
void LTimer::set_second( luint32 p ) {
    LMutex mutex; // Мьютекс
    LMutexLock locker( &mutex ); // Локер
    _interval = p * 1000;
}

Автор: georain 11.6.2008, 01:14
Нет не секу, расскажи.

Автор: andrew_121 11.6.2008, 01:30
Код


class Primary {
public:
   Primary():stat(false) {}
   bool GetStat() const { return stat; }
   void SetStat(bool st) { stat = st; }
private:
   bool stat;
};

int main() {

   Primary primary;

   Thread thread1, thread2;
   // Кароче. "thread1" и "thread2", в произвольном порядке, вызывают методы GetStat() и SetStat() объекта Primary.
   // У одного из них, результат работы зависит, от полученного значения. Какой из них будет получать правильное значение?

   return 0;
}


Автор: georain 11.6.2008, 01:35
Цитата(andrew_121 @  11.6.2008,  01:30 Найти цитируемый пост)
Какой из них будет получать правильное значение?

А какой из них будет получать правильное значение при наличии блокировки?
Другими словами, что изменится при введении блокировок в твой пример?

Автор: andrew_121 11.6.2008, 01:39
А вот тут тебе нужно позаботиться о синхронизации.

Автор: georain 11.6.2008, 01:44
Добавление блокировок в твой пример ничего не даст, а "позаботится о синхронизации" имхо означает создание полезного кода из бесполезного примера.
andrew_121, давай прервём нашу беседу до прихода специалистов.

Добавлено через 13 минут и 23 секунды
ИМХО, при использовании bool блокировать нужно только в конструкции
Код

lock()
    if( a == true ) a = false;
    else            a = true;
unlock()

и производных от неё. Все остальные случаи представляют собой только а) чтение и б) запись без предварительного чтения, а значит не нуждаются в синхронизации.
Я могу быть не прав! Поправьте меня аргументами или примерами

Автор: Palladin 11.6.2008, 05:26
Цитата(georain @  10.6.2008,  23:49 Найти цитируемый пост)
Честно говоря я не вижу смысла её тут ставить.

Не видете смысла, не ставьте, если смысл появится вы, по всей видимости, это поймете и сделаете, то что нужно! 
Не ждите "специалистов", какие гарантии что их ответ верен? 
Не полагайтесь на истину авторитета, полагайтесь на авторитет истины smile 
P.S. Слушать кого-то нужно лишь в случае когда надо срочно что-то делать, а вы незнаете как, сейчас по всей видимости вы изучаете, а значит изучайте smile

Добавлено через 2 минуты и 36 секунд
И не зачем грубить форумчанам, если вы не заметили andrew_121, изо всех сил старался помочь... 

Автор: Lazin 11.6.2008, 05:36
bool - атомарный тип, причем значение ему обычно присваивается, не прибавляется, не вычитается и тд... так что можно без блокировок обойтись..
блокировать нужно немного по другому
Код

bool need_to_work = true;
...
lock();
if (need_to_work)
{
    need_to_work = false;
    //код который должен выполнится 1 раз
}
unlock();

если здесь не блокировать то код может выполнится 2 раза и более
в принципе могут портиться даже переменные атомарных типов, если они изменяются одновременно из разных потокв, но поскольку для bool актуально только присваивание и сравнение, то тут
Цитата

Код

class Primary {
public:
   Primary():stat(false) {}
   bool GetStat() const { return stat; }
   void SetStat(bool st) { stat = st; }
private:
   bool stat;
};


можно вообще не блокировать..

Автор: georain 11.6.2008, 08:43
Цитата(Palladin @  11.6.2008,  05:26 Найти цитируемый пост)
И не зачем грубить форумчанам, если вы не заметили andrew_121, изо всех сил старался помочь...  

Я ни в коем случае не хотел нагрубить, andrew_121, если я вас обидел, сильно прошу прощения. Я благодарен за вашу помощь, она навела на правильные мысли smile

Lazin, спасибо!

Т.е. в случае:
Код

bool need_to_do_it = true; // изменяется в одном потоке
...

if( need_to_do_it ) // выполняется в другом потоке
{
    //код в котором нет обращений к need_to_do_it
}

блокировать где-либо не надо?

А таком случае:
Код

int var = 123; // изменяется в одном потоке
...

if( var == 500 ) // выполняется в другом потоке
{
    //код в котором нет обращений к var
}

в "другом" потоке (с if) блокировать тоже не надо?

Автор: Palladin 11.6.2008, 09:26
Вы видимо про else данного иф, ненадо

Автор: Lazin 11.6.2008, 09:32
если операция сравнения и присваивания для инт атомарна, тоесть переключение контекста не может произойти во время операции с этим типом, то не надо..
но если операция не атомарна, то она может выполняться так:

в случае одного потока:
__________________________________________
var == 10
копирование в регистр из памяти значения переменной    reg = var; reg == 10
изменение значения                                                               reg += 10 
копировани из регистра в память                                          var = reg
var == 20

2 потока:
1й поток                                           2й поток
__________________________________________________________________________________
var == 10
копирование в регистр из памяти значения переменной                                                                          reg1 = var

                                                           копирование в регистр из памяти значения переменной               reg2 = var; reg2 == 10
                                                           изменение значения                                                                          reg2 += var
                                                           копирование из регистра в память                                                   var = reg2; var == 20

изменение значения в регистре 
(оно не учитывает изменения внесенные 2-м потоком)
                                                                              reg1 += 10; reg1 == 20
копирование из регистра в память                                                                                                              var = reg1; var == 20!!
var == 20

Добавлено @ 09:44
конечно шансов что так произойдет мало.. и в большинстве случаев в переменную запишется значение 30, но все-же
проще все-же разрабатывать систему блокировок на уровне классов.. для разных объектов должны быть свои блокировки, вот так, на уровне кода очень сложно это делать..
я обычно использую блокировки вот так:

Код

void method()//метод изменяет объект, 
//когда он выполняется другие методы этого объекта должны ждать
//ждет когда отработают все методы method2 в других потоках
{
  lock_read_and_write();
  ///code
  unlock();
}

void method2() const //метод не изменяет объект, 
//можно одновременно вызывать из разных потоков
//но только если не вызван метод method в одном из потоков
{
  lock_write();
  //code
  unlock();
}


lock_write - блокировка изменения объекта - shared read
lock_read_and_write - блокировка записи и чтения - exclusive write

Автор: georain 11.6.2008, 09:53
Картина становится ясна. А операции "чтение" и "запись (без предварительного чтения в регистр)" всегда атомарны? Переключение контекста может произойти во время этих операций? Т.е. например в памяти находится 01, первый поток хочет записать 10, а  второй поток в это время читает, может он в итоге прочитать 11 или 00, или всегда либо 01 либо 10?

Автор: Lazin 11.6.2008, 10:00
на платформе х86 будет либо 10 либо 01, на остальных скорее всего то-же smile 

Автор: georain 11.6.2008, 10:06
Цитата(Lazin @  11.6.2008,  09:32 Найти цитируемый пост)
проще все-же разрабатывать систему блокировок на уровне классов

Да, конечно. Но блокировка дело не дешёвое и делать её для чтения bool как в примере по моему неразумно. Вот и хочется понять в каких случаях без неё можно обойтись.
Например то что тут
Код

class Primary {
public:
   Primary():stat(false) {}
   bool GetStat() const { return stat; }
   void SetStat(bool st) { stat = st; }
private:
   bool stat;
};

можно вообще не блокировать мои коллеги сомневаются и ставят mutex. smile
Может какая литература есть?

Автор: vinter 11.6.2008, 10:10
я бы ставил блокировку в месте использования данного класса, а уж никак ни в его методах

Автор: Lazin 11.6.2008, 10:11
в этом примере ничего блокировать не надо

Автор: andrew_121 11.6.2008, 10:15
Вот, и меня просветили. Я бы поставил.

Автор: georain 11.6.2008, 10:16
vinter, это ухудшает инкапсуляцию, есть паттерн типа "защищённый класс", все открытые методы начинаются с блокировки. Тогда не надо заботится о защите данных класса. Кроме того это уменьшает область критического кода, да и вообще количество возможных ошибок. Иногда блокировок ой как много бывает.

Автор: vinter 11.6.2008, 10:27
Цитата(georain @  11.6.2008,  11:16 Найти цитируемый пост)
vinter, это ухудшает инкапсуляцию, есть паттерн типа "защищённый класс", все открытые методы начинаются с блокировки. Тогда не надо заботится о защите данных класса. Кроме того это уменьшает область критического кода, да и вообще количество возможных ошибок. Иногда блокировок ой как много бывает.

зависит от назначения класса, если будет библиотека, то внутренние блокировки не айс, как пример STL

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)