Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

53501_3_MartynovSA_lab3

.pdf
Скачиваний:
20
Добавлен:
29.04.2015
Размер:
1.3 Mб
Скачать

тому же ресурсу, но означают разные условия. Операция ожидания атомарно освобождает мьютекс и блокирует процесс до момента уведомления о том, что условие выполнено[4].

В листинге 18 происходит инициализация условных переменных, но для организации полноценной работы их не достаточно. Поэтому в качестве вспомогательного объекта синхронизации используется критическая секция.

Листинг 18: Основной файл инициализации примитивов синхронизации (src/SynchronizationPrimitives/ConditionVariable/main.cpp)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#include < windows .h >

#include < string .h >

#include < stdio .h >

#include < conio .h >

#include < tchar .h >

#include " thread .h"

#include " utils .h"

#include " Logger .h"

//глобальные переменные:

struct FIFOQueue queue ; // ст

р

уктур

а очере

ди

struct Configuration config ; // кон

фигурация программы

bool isDone = false ;

// Признак зав

ершения

 

HANDLE * allhandlers ;

// массив

всех

создаваемых потоков

// критическая секция общая и для писателей и для читателей

CRITICAL_SECTION crs ;

// условная переменная для потоков -писателей

CONDITION_VARIABLE condread ;

// условная переменная для потоков -читателей

CONDITION_VARIABLE condwrite ;

int _tmain ( int argc , _TCHAR * argv []) {

Logger log ( _T (" ConditionVariable "));

if ( argc < 2)

// Используем конфигурацию по -умолчанию

SetDefaultConfig (& config , & log );

else

// Загрузка конфига из файла

SetConfig ( argv [1] , & config , & log );

// создаем необходимые потоки без их запуска

CreateAllThreads (& config , & log );

41

37// Инициализируем очередь

38queue . full = 0;

39queue . readindex = 0;

40queue . writeindex = 0;

41queue . size = config . sizeOfQueue ;

42 queue . data = new _TCHAR *[ config . sizeOfQueue ];

43// инициализируем средство синхронизации

44InitializeCriticalSection (& crs );

45InitializeConditionVariable (& condread );

46InitializeConditionVariable (& condwrite );

47

 

48

// запускаем потоки на исполнение

49

for ( int i = 0; i < config . numOfReaders + config . numOfWriters + 1; i ++)

50

ResumeThread ( allhandlers [i ]) ;

51

 

52// ожидаем завершения всех потоков

53WaitForMultipleObjects ( config . numOfReaders + config . numOfWriters + 1,

54allhandlers , TRUE , 5000) ;

55

 

56

// закрываем handle потоков

57

for ( int i = 0; i < config . numOfReaders + config . numOfWriters + 1; i ++)

58CloseHandle ( allhandlers [i ]) ;

59// удаляем объект синхронизации

60DeleteCriticalSection (& crs );

61

 

62

// Очистка памяти

63

for ( size_t i = 0; i != config . sizeOfQueue ; ++ i)

64if ( queue . data [i ])

65free ( queue . data [i ]) ; // _wcsdup использует calloc

66delete [] queue . data ;

67

68// Завершение работы

69log . loudlog ( _T (" All tasks are done !"));

70_getch () ;

71return 0;

72}

Читатели (листинг 19) и писатели (листинг 20) входят в критическую секцию, но для работы ожидают условную переменную.

Листинг 19: Потоки читатели, синхронизация через условные переменные и критические секции (src/SynchronizationPrimitives/ConditionVariable/threadReader.cpp)

1 # include < windows .h >

2 # include < stdio .h >

3

42

4

# include " utils .h"

5

 

 

6

DWORD

WINAPI ThreadReaderHandler ( LPVOID prm ) {

7

int

myid = ( int ) prm ;

8

 

 

9Logger log ( _T (" ConditionVariable . ThreadReader ") , myid );

10extern bool isDone ;

11extern struct FIFOQueue queue ;

12extern struct Configuration config ;

13extern CRITICAL_SECTION crs ;

14extern CONDITION_VARIABLE condread ;

15extern CONDITION_VARIABLE condwrite ;

16

17while ( isDone != true ) {

18// Захват объекта синхронизации

19log . quietlog ( _T (" Waining for Critical Section "));

20EnterCriticalSection (& crs );

21log . quietlog ( _T (" Get Critical Section "));

22

 

 

23

log . quietlog ( _T (" Waining for empty space in the

queue "));

24

while (!( queue . readindex != queue . writeindex ||

queue . full == 1) )

25

// спим пока в очереди не появятся данные

 

26SleepConditionVariableCS (& condread , &crs , INFINITE );

27log . quietlog ( _T (" Get space in the queue "));

28

29// взяли данные , значит очередь не пуста

30queue . full = 0;

31// печатаем принятые данные

32

log . loudlog ( _T (" Reader %d get data : \"% s \" from position %d") , myid ,

33

queue . data [ queue . readindex ], queue . readindex );

34

free ( queue . data [ queue . readindex ]) ;

// очищаем очередь от данных

35

queue . data [ queue . readindex ] = NULL ;

 

36

queue . readindex = ( queue . readindex

+ 1) % queue . size ;

37

 

 

38// шлем сигнал потокам -читателям

39log . quietlog ( _T (" Wake Condition Variable "));

40WakeConditionVariable (& condwrite );

41// освобождение синхронизируемого объекта

42log . quietlog ( _T (" Leave Critical Section "));

43LeaveCriticalSection (& crs );

44

45// задержка

46Sleep ( config . readersDelay );

47}

48log . loudlog ( _T (" Reader %d finishing work ") , myid );

43

49 return 0;

50 }

Листинг 20: Потоки писатели, синхронизация через условные переменные и критические

секции (src/SynchronizationPrimitives/ConditionVariable/threadWriter.cpp)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

#include < windows .h >

#include < stdio .h >

#include < tchar .h >

#include " utils .h"

DWORD WINAPI ThreadWriterHandler ( LPVOID prm ) {

int myid = ( int ) prm ;

Logger log ( _T (" ConditionVariable . ThreadWriter ") , myid );

extern

bool isDone ;

 

 

 

extern struct FIFOQueue queue ;

 

 

 

extern struct Configuration config ;

 

extern CRITICAL_SECTION crs ;

 

 

 

extern CONDITION_VARIABLE condread ;

 

extern

CONDITION_VARIABLE condwrite ;

 

_TCHAR

tmp [50];

 

 

 

int msgnum = 0; // номер передаваемого сообщения

 

while ( isDone != true ) {

 

 

 

// Захват синхронизирующего объекта

 

log . quietlog ( _T (" Waining for

Critical Section "));

EnterCriticalSection (& crs );

 

 

 

log . quietlog ( _T (" Get Critical Section "));

 

log . quietlog ( _T (" Waining for empty space in the queue "));

while

(!( queue . readindex != queue . writeindex

|| ! queue . full == 1) )

// спим пока в очереди не освободится место

 

SleepConditionVariableCS (& condwrite , &crs ,

INFINITE );

log . quietlog ( _T (" Get space in the queue "));

 

// заносим в очередь данные

 

 

 

swprintf_s (tmp , _T (" writer_id

=

%d numMsg = %3 d") , myid , msgnum );

queue . data [ queue . writeindex ]

=

_wcsdup ( tmp );

 

msgnum ++;

 

 

 

// печатаем принятые данные

log . loudlog ( _T (" Writer %d put data : \"% s \" in position %d") , myid ,

queue . data [ queue . writeindex ], queue . writeindex );

44

40

queue . writeindex = ( queue . writeindex + 1) % queue . size ;

41

// если очередь заполнилась

42

queue . full = queue . writeindex == queue . readindex ? 1 : 0;

43

 

44if ( queue . full == 1)

45log . loudlog ( _T (" Queue is full "));

46// шлем сигнал потокам -читателям

47log . quietlog ( _T (" Wake Condition Variable "));

48WakeConditionVariable (& condread );

49// освобождение синхронизируемого объекта

50log . quietlog ( _T (" Leave Critical Section "));

51LeaveCriticalSection (& crs );

52

53// задержка

54Sleep ( config . writersDelay );

55}

56log . loudlog ( _T (" Writer %d finishing work ") , myid );

57return 0;

58}

45

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

Рис. 6: Условные переменные и критические секции.

46

1.6Задача читатели-писатели (для потоков одного процесса)

Рассмотрим частный случай этой задачи для демонстрации использования объектовсобытий для синхронизации доступа к памяти.

Задание: необходимо решить задачу одного писателя и N читателей. Для синхронизации разрешено использовать только объекты-события, в качестве разделяемого ресурса – разделяемую память (share memory). Писатель пишет в share memory сообщение и ждёт, пока все читатели не прочитают данное сообщение.

Задача должна быть решена сначала для потоков, принадлежащих одному процессу, а затем – разным независимым процессам.

Для этой задачи были внесены некоторые изменения в файл с сервисными функциями, которые позволили запустить только один поток-писатель. Примитивы синхронизации (события) и общая память инициализируются в листинге 21, а используются писателем и читателями в листинге 22 и 23[1].

Листинг 21: Основной файл (src/SynchronizationPrimitives/ThreadsReaderWriter/main.cpp)

1 # include < windows .h >

2 # include < string .h >

3 # include < stdio .h >

4 # include < conio .h >

5 # include < tchar .h >

6

7 # include " thread .h"

8 # include " utils .h"

9 # include " Logger .h"

10

11// глобальные переменные:

12struct Configuration config ; // конфигурация программы

13bool isDone = false ; // флаг завершения

14

HANDLE * allhandlers ; // массив всех создаваемых

потоков

 

15

 

 

 

 

 

 

 

 

16 // события для синхронизации:

 

 

 

 

 

17

HANDLE canReadEvent ; // писатель записал сообщение

(ручной

сброс);

18

HANDLE canWriteEvent ; // все

 

читатели

готовы к

при

ему след

ующего (автосброс);

19

HANDLE allReadEvent ; // все ч

итатели прочитали

соо

бщение (

ручной сброс);

20

HANDLE changeCountEvent ; //

р

азрешение работы с

о с

четчиком

(автосброс);

21

HANDLE exitEvent ;

// завершение программы (ручной

сброс);

 

22

 

 

 

 

 

 

 

 

23 // переменные для синхронизации работы потоков:

 

 

 

24

int countread = 0;

// число

 

потоков , которое уже

прочитали данные

25 //

(устанавливается писателем

и изменяется

47

26 //

читателями после прочтения сообщения)

27

int countready = 0; // число потоков , готовых для чтения сообщения

28 //

(ожидающих сигнала от писателя)

29

 

 

30 // имя разделяемой памяти

31

wchar_t

shareFileName [] = L" $$MyVerySpecialShareFileName$$ ";

32

 

 

33HANDLE hFileMapping ; // объект -отображение файла

34// указатели на отображаемую память

35LPVOID lpFileMapForWriters ;

36LPVOID lpFileMapForReaders ;

37

38 int _tmain ( int argc , _TCHAR * argv []) {

39 Logger log ( _T (" ThreadsReaderWriter "));

40

41if ( argc < 2)

42// Используем конфигурацию по -умолчанию

43

SetDefaultConfig (& config , & log );

44else

45// Загрузка конфига из файла

46SetConfig ( argv [1] , & config , & log );

47

 

 

 

 

 

 

 

 

 

48

// создаем необходимые

потоки без

их

запуска

 

 

49

CreateAllThreads (& config ,

& log );

 

 

 

 

50

 

 

 

 

 

 

 

 

 

51

// Инициализируем ресурс ( share memory ): создаем

объект

"отображаемый файл"

52

// будет использован системный

файл

подкачки (на диске

файл создаваться

53

// не будет) , т.к. в качестве дескриптора файла

использовано значение

54

// равное 0 xFFFFFFFF (его

эквивалент - символическая константа

 

INVALID_HANDLE_VALUE )

 

 

 

 

 

 

55

if (( hFileMapping = CreateFileMapping ( INVALID_HANDLE_VALUE , NULL ,

56

PAGE_READWRITE , 0, 1500 ,

shareFileName )) == NULL ) {

 

57

// INVALID_HANDLE_VALUE - дескриптор открытого файла

 

58

//

 

 

( INVALID_HANDLE_VALUE - файл подкачки)

59

// NULL - атрибуты защиты объекта -отображения

 

 

60

// PAGE_READWRITE - озможности доступа к представлению файла при

61

//

 

отображении ( PAGE_READWRITE - чтение/запись)

62

// 0, 1500

- старшая

и младшая

части значения

максимального

63

//

размера объекта отображения файла

 

64// shareFileName - имя объекта -отображения.

65log . loudlog ( _T (" Impossible to create shareFile , GLE = %d") ,

66GetLastError () );

67ExitProcess (10000) ;

68}

69// отображаем файл на адресное пространство нашего процесса для потока -писа

48

теля

70 lpFileMapForWriters = MapViewOfFile ( hFileMapping , FILE_MAP_WRITE , 0, 0, 0)

;

71// hFileMapping - дескриптор объекта -отображения файла

72// FILE_MAP_WRITE - доступа к файлу

73

// 0, 0 - старшая

и

младшая

части

смещения начала

отображаемого участка в

 

файле

 

 

 

 

 

 

 

 

74

//

(0 - начало отображаемого участка

совпадает с началом файла)

75

// 0 - размер

отображаемого участка файла в

байтах (0 - весь файл)

76

 

 

 

 

 

 

 

 

 

77

// отображаем файл на адресное пространство нашего

процесса для потоков -чит

 

ателей

 

 

 

 

 

 

 

 

78

lpFileMapForReaders

= MapViewOfFile ( hFileMapping ,

FILE_MAP_READ , 0, 0, 0) ;

79

 

 

 

 

 

 

 

 

 

80

// инициализируем средства синхронизации

 

 

81

// (атрибуты защиты , автосброс , начальное состояние , имя):

82

// событие "окончание записи" (можно читать) , ручной сброс , изначально заня

 

то

 

 

 

 

 

 

 

 

83

canReadEvent = CreateEvent ( NULL , true , false , L"");

84

// событие - "можно писать",автосброс(разрешаем писать только одному) , изна

 

чально свободно

 

 

 

 

 

 

85

canWriteEvent = CreateEvent ( NULL , false , false , L"");

86

// событие "все прочитали"

 

 

 

 

87

allReadEvent = CreateEvent ( NULL , true , true , L"");

 

88

// событие для изменения счетчика (сколько клиентов еще не прочитало сообще

 

ние)

 

 

 

 

 

 

 

 

89

changeCountEvent = CreateEvent ( NULL , false , true , L"");

90

// событие "завершение работы программы", ручной сброс , изначально занято

91

exitEvent =

CreateEvent ( NULL , true ,

false , L"");

 

92

 

 

 

 

 

 

 

 

 

93

// запускаем потоки -писатели и поток -планировщик на исполнение

94

for ( int i

= 0; i

<

config . numOfReaders + config . numOfWriters + 1; i ++)

95

ResumeThread ( allhandlers [i ]) ;

 

 

 

96

 

 

 

 

 

 

 

 

 

97// ожидаем завершения всех потоков

98WaitForMultipleObjects ( config . numOfReaders + config . numOfWriters + 1,

99allhandlers , TRUE , INFINITE );

100

 

101

// закрываем handle потоков

102

for ( int i = 0; i < config . numOfReaders + config . numOfWriters + 1; i ++)

103

CloseHandle ( allhandlers [i ]) ;

104

 

105// закрываем описатели объектов синхронизации

106CloseHandle ( canReadEvent );

107CloseHandle ( canWriteEvent );

49

108CloseHandle ( allReadEvent );

109CloseHandle ( changeCountEvent );

110CloseHandle ( exitEvent );

111

112// закрываем handle общего ресурса

113UnmapViewOfFile ( lpFileMapForReaders );

114UnmapViewOfFile ( lpFileMapForWriters );

115

116// закрываем объект "отображаемый файл"

117CloseHandle ( hFileMapping );

118

 

119

// Завершение работы

120

log . loudlog ( _T (" All tasks are done !"));

121

_getch () ;

122

return 0;

123

}

Листинг 22: Единственный поток-писатель (src/SynchronizationPrimitives/ThreadsReaderWriter/threadWriter.cpp)

1

# include < windows .h >

2

# include < stdio .h >

3

# include

< tchar .h >

4

 

 

5

# include

" utils .h"

6

 

 

7

DWORD WINAPI ThreadWriterHandler ( LPVOID prm ) {

8

int myid = ( int ) prm ;

9

 

 

10Logger log ( _T (" ThreadsReaderWriter . ThreadWriter ") , myid );

11extern bool isDone ;

12extern struct Configuration config ;

13

14extern HANDLE canReadEvent ;

15extern HANDLE canWriteEvent ;

16extern HANDLE exitEvent ;

17

18extern int countread ;

19extern LPVOID lpFileMapForWriters ;

20

21int msgnum = 0;

22HANDLE writerhandlers [2];

23writerhandlers [0] = exitEvent ;

24writerhandlers [1] = canWriteEvent ;

25

50

Соседние файлы в предмете Системное программное обеспечение