Шаг 78 - Что понимается под условиями гонки (rase condition) ?

Создание больших приложений подразумевает, что к одним и тем же данным будут производиться множественные обращения и как результат может появиться ситуация, при которой время обращения существенно влияет на результат. Чтобы это было более понятно давайте рассмотрим простой пример. У нас есть объект бухгалтерского счета. Смотрите код.

// PotocTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"
#include "iostream.h"

class Cchet10
{
public:
	Cchet10();
	void Set(double summ);
	double Get();
private:
	double count;
};


Cchet10::Cchet10()
{
	count=0;
}

void Cchet10::Set(double summ) 
{
	count=summ;
}

double Cchet10::Get()
{
	return count;
}

void main()
{
	Cchet10 ch;
	ch.Set(ch.Get()+123); 
	cout << ch.Get() << endl; 
}

Вот у нас есть объект счета 10, и метод set, который устанавливает новое значение счета. При однопотоковой работе в одном приложении все нормально. Но вот только нам нужно несколько потоков. Если вдруг к этому объекту начнет обращаться насколько пользователей все станет хуже. Давайте cэмитируем многопотоковый доступ.

// PotocTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
#include "process.h" 
#include "iostream.h"
#include "stddef.h"
#include "stdlib.h"


class Cchet10
{
public:
	Cchet10();
	void Set(double summ);
	double Get();
private:
	double count;
};

Cchet10::Cchet10()
{
	count=0;
}

void Cchet10::Set(double summ) 
{
	count=summ;
}

double Cchet10::Get()
{
	return count;
}

Cchet10 ch;

void set1(void *);
void set2(void *);

void main()
{
	ch.Set(20); 
	if (_beginthread(set1,1024,NULL)==-1)
		cout << "Error begin thread " << endl; 
	if (_beginthread(set2,1024,NULL)==-1)
		cout << "Error begin thread " << endl; 
	Sleep(10000);
	cout << ch.Get() << endl; 
}

void set1(void *)
{
	Sleep(1000);
	cout << "set1" << endl;
	ch.Set(10); 
	_endthread();
}

void set2(void *)
{
	cout << "set2" << endl;
	ch.Set(ch.Get()+2000); 
	_endthread();
}

Не забудьте при компиляции установить опцию многопотокового приложения.

78_1.gif (4045 b)

Так вот результат выполнени этой программы будет такой:

set2
set1
10
Press any key to continue

Посмотрите на код, я в конце main даже Sleep поставил, чтобы приложение не завершилось раньше потока. По какой причине задержка set1 - только для демонстрации. Это может оператор пошел чай попить или еще что-то. Конечно пока все это происходит в рамках одной программы это немного натянуто, но если представить два потока как два пользователя, то все становится намного реальнее. А основная проблема в том, что данные у нас разделяемые и к ним может быть многочисленный доступ.


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Каев Артем - 16.03.2001