Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС Laba2 Саттаров РР.doc
Скачиваний:
7
Добавлен:
29.07.2019
Размер:
97.79 Кб
Скачать
  1. Что такое критические секции и для чего они используются?

Критическая секция (critical section) — это небольшой участок кода, требующий монопольного доступа к каким-то общим данным. Она позволяет сделать так, чтобы единовременно только один поток получал доступ к определенному ресурсу. Естественно, система может в любой момент вытеснить поток и подключить к процессору другой, но ни один из потоков, которым нужен занятый ресурс, не получит процессорное время до тех пор, пока поток не выйдет за границы критической секции.

  1. Какие правила необходимо соблюдать при использовании критических секций?

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

На каждый разделяемый ресурс следует использовать отдельную структуру CRITICAL_SECTION.

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

Одновременный доступ к нескольким ресурсам.

Иногда нужен одновременный доступ сразу к двум структурам данных. Тогда ThreadFunc можно реализовать так:

DWORD WINAPI ThreadFunc(PVOID pvParam) {

EnterCriticalSection(&g_csNums);

EnterCriticalSection(&g_csChars);

// в этом цикле нужен одновременный доступ к обоим ресурсам

for (int x = 0; x < 100; x++) g_nNums[x] = g_cChars[x];

LeaveCriticalSection(&g_csChars);

LeaveCrilicalSection(&g_csNums};

return(0); }

Предположим, доступ к обоим массивам требуется и другому потоку в данном процессе; при этом его функция написана следующим образом:

DWORD WINAPI OtherThreadFunc(PVOID pvParam) {

EnterCriticalSection(&g_csChars); EnterCriticalSection(&g_csNums);

for (int x = 0; x < 100; x++) g_nNums[x] = g_cChars[x]; LeaveCriticalSection(&g_csNums); LeaveCriticalSection(&g_csChars); return(0);

}

Изменен порядок вызовов EnterCriticalSection и LeaveCriticalSection. Но из за того, что функции ThreadFunc и OtherThreadFunc написаны именно так, существует вероятность взаимной блокировки (deadlock). Допустим, ThreadFunc начинает исполнение и занимает критическую секцию g_nNums. Получив от системы процессорное время, поток с функцией OtherThreadFunc захватывает критическую секцию g_cChars. Тут-то и происходит взаимная блокировка потоков. Какая бы из функций — ThreadFunc или OtherThreadFunc — ни пыталась продолжить исполнение, она не сумеет занять другую, необходимую ей критическую секцию. Эту ситуацию легко исправить, написав код обеих функций так, чтобы они вызывали EnterCriticalSection в одинаковом порядке. Заметьте, что порядок вызовов LeaveCrititalSection несуществен, поскольку эта функция никогда не приостанавливает поток.

Не следует занимать критические секции надолго.

Надолго занимая критическую секцию, приложение может блокировать другие потоки, что отрицательно скажется на его общей производительности. Вот прием, позволяющий свести к минимуму время пребывания в критической секции. Следующий код не даст другому потоку изменять значение в g_сs до тех пор, пока в окно не будет отправлено сообщение WM_SOMEMSG.

SOMESTRUCT g_s; CRITICAL_SECTION g_cs;

DWORD WINAPI SomeThread(PVOID pvParam) {

EnterCriticalSection(&g_cs);

// посылаем в окно сообщение SendMessage(hwndSomeWnd, WM_SOMEMSG, &g_s, 0); LeaveCriticalSection(&g_cs); return(0);

}

Трудно сказать, сколько времени уйдет на обработку WM_SOMEMSG оконной процедурой — может, несколько миллисекунд, а может, и несколько лет. В течение этого времени никакой другой поток не получит доступ к структуре g_сs. Поэтому лучше составить код иначе

SOMESTRUCT g_s; CRITICAL_SECTION g_cs;

DWORO WINAPI SomeThread(PVOID pvParam) {

EnterCriticalSection(&g_cs); SOMESTRUCT sTemp = g_s; LeaveCriticalSection(&g_cs);

// посылаем в окно сообщение SendMessage(hwndSompWnd, WM_SOMEMSG, &sTemp, 0); return(0);

}

Этот код сохраняет значение элемента g_s, во временной переменной sTemp. Нетрудно догадаться, что на исполнение этой строки уходит всего несколько тактов процессора. Далее программа сразу вызывает LeaveCriticalSection — защищать глобальную структуру больше не нужно. Так что вторая версия программы намного лучше первой, поскольку другие потоки «отлучаются» от структуры g_s лишь на несколько тактов процессора, а не на неопределенно долгое время. Такой подход предполагает, что «моментальный снимок» структуры вполне пригоден для чтения оконной процедурой, а также что оконная процедура не будет изменять элементы этой структуры.

Листинг программы

#include "stdafx.h"

#include "stdio.h"

#include "conio.h"

#include "windows.h"

CRITICAL_SECTION g_cs;

DWORD WINAPI ThreadFunc(PVOID pvParam)

{ char *s=(char*) pvParam;

printf(s);

DWORD dwResult = 0;

while (1)

{Sleep (1000);

EnterCriticalSection(&g_cs);

printf("\n\n Potok Zapushen");

int kol=0;

for ( int i=0; i<strlen(s); i++)

if (s[i]>='A' && s[i]<='Z')

{

kol++;

printf("\n naidena zagl Bukva= %c", s[i] );

}

printf("\n ishodnaya stroka: %s", s);

printf("\n V Summe kolichestvo zaglavnih = %d", kol);

LeaveCriticalSection(&g_cs);

}

return(dwResult);

}

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{ char *s=(char*) pvParam;

printf(s);

DWORD dwResult = 0;

while (1)

{Sleep (1000);

EnterCriticalSection(&g_cs);

for ( int i =0; i<strlen(s); i++)

s[i]=rand()%48+48;

LeaveCriticalSection(&g_cs);

}

return(dwResult);

}

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

{DWORD id;

char str[20]="STR Pered";

InitializeCriticalSection(&g_cs);

HANDLE h=CreateThread(NULL, 0, ThreadFunc,str,CREATE_SUSPENDED,&id);

HANDLE h2=CreateThread(NULL, 0, ThreadFunc2,str,0,&id);

while(1)

{

char k=getch();

if (k=='1') ResumeThread(h);

if (k=='2')

{SuspendThread(h);

printf("\n Potok 1 ostanovlen");

}

if (k=='3') ResumeThread(h2);

if (k=='4')

{SuspendThread(h2);

printf("\n Potok 2 ostanovlen");

}

if (k=='5') {TerminateThread(h, 0);;

printf("\n Ubit 1 potok ");

}

if (k=='6') {TerminateThread(h2, 0);;

printf("\n Ubit 2 potok ");

}

if (k=='7') {h=CreateThread(NULL, 0, ThreadFunc,str,CREATE_SUSPENDED,&id);

printf("\n Rozden 1 potok ");

}

if (k=='8') {h2=CreateThread(NULL, 0, ThreadFunc,str,CREATE_SUSPENDED,&id);

printf("\n Rozden 2 potok ");

}

}

getch();

return 0;

}