Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб-07(Shinhron) Синхронизация потоков.DOC
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
327.68 Кб
Скачать

2.5.События с автоматическим сбросом

Объекты "события с автоматическим сбросом" больше похожи на семафоры и объекты mutex, чем на события со сбросом вручную. Когда поток вызывает SetEvent, чтобы освободить событие, оно остается в таком состоянии, пока не пробудится другой поток, ожидающий тот же объект. За мгновение до возобновления работы потока система автоматически переводит событие в занятое состояние. Применение объекта "событие с автоматическим сбросом" позволяет возобновить исполнение лишь какого-то одного из ожидающих потоков. Прочие потоки по-прежнему "спят" и ждут. Решение о том, какой именно из ждущих потоков возобновит исполнение, система принимает самостоятельно. Это относится не только к событиям, но и ко всем синхронизирующим объектам. Но если у ждущих потоков разный приоритет, первым возобновит исполнение тот, у кого он наивысший.

Этим типом событий, как и событиями со сбросом вручную, управляют функции SetEvent, ResetEvent и PulseEvent. ResetEven обычно не используют, т. к. система перед возвратом из WaitForSingleObject и WaitForMultipleObjects автоматически сбрасывает (переводит в занятое состояние) эти объекты.

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

3. СОДЕРЖАНИЕ ОТЧЕТА

  1. Постановка задачи.

  2. Состав и структура программного модуля.

  3. Блок-схема алгоритма.

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

  5. Протокол диалога и выходные данные программы.

  6. Анализ полученных результатов.

ЛИТЕРАТУРА

  1. Кинг А. Windows 95 изнутри/Перев. с англ. - СПб: Питер, 1995. - 512 с.

  2. Мэтт П. Секреты системного программирования в Windows 95.- Киев: издательство "Диалект", 1996. - 448 с.

  3. Рихтер Д. Windows для профессионалов (программирование в Win32 API для Windows NT 3.5и Windows 95).Пер. с англ. - М.: Издательский отдел "Русская редакция" ТОО "Channel Trading Ltd.",1995. - 720 с.

ПРИЛОЖЕНИЕ

/*****************************************************************

Модуль: CritSecs.C

*****************************************************************/

#include "..\afxres.h"

#include <windows.h>

#include <windowsx.h>

#include "..\AdvWin32.H"

#pragma warning(disable: 4001) /* Одностроковый комментарий */

#include <tchar.h>

#include <stdio.h> // для sprintf

#include <process.h> // для _beginthreadex

//////////////////////////////////////////////////////////////////

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

HWND g_hwndDlg = NULL;

HANDLE g_hThreadCntr = NULL;

HANDLE g_hThreadDspy = NULL;

// Данные, подлежащие защите

int g_szNumber = 0;

// Критический раздел, используемый для защиты этих данных

CRITICAL_SECTION g_CriticalSection;

//////////////////////////////////////////////////////////////////

// Добавление строки в окно списка

void AddToListBox(LPCTSTR szBuffer) {

HWND hwndDataBox = GetDlgItem(g_hwndDlg, IDC_DATABOX);

int x = ListBox_AddString(hwndDataBox, szBuffer);

ListBox_SetCurSel(hwndDataBox, x);

if (ListBox_GetCount(hwndDataBox) > 100)

ListBox_DeleteString(hwndDataBox, 0);

}

//////////////////////////////////////////////////////////////////

// Поток, который увеличивает счетчик защищенных данных

void CounterThread (LPVOID lpThreadParameter) {

unsigned int nNumber, nDigit;

BOOL fSyncChecked;

for (;;) {

// Узнаем состояние флажка Synchronize и запоминаем его

fSyncChecked =

IsDlgButtonChecked(g_hwndDlg, IDC_SYNCHRONIZE);

if (fSyncChecked) {

// Если пользователь хочет синхронизировать потоки

EnterCriticalSection(&g_CriticalSection);

}

// Преобразуем символьное представление числа в целое значение и добавляем 1

_stscanf(g_szNumber, __TEXT("%d"), &nNumber);

g_szNumber++;

// Преобразуем новое число в строку

/* */ nDigit = 0;

while (nNumber != 0) {

// Помещаем разряд числа в строку

g_szNumber[nDigit++] = (TCHAR)

(__TEXT("0") + (nNumber % 10));

// Вызов здесь функции Sleep сообщает системе, что неиспользованный остаток текущего

// кванта времени нужно отдать другому потоку. Этот вызов необходим в однопроцессорной

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

// очевидны. Обычно в программах функцию Sleep для этого не вызывают.

Sleep(0);

// Готовимся получить следующий разряд

nNumber /= 10;

}

// Все разряды преобразованы в строку.

// Завершаем строку.

g_szNumber[nDigit] = 0;

// Символы сформированы в обратном порядке: восстанавливаем нормальный порядок.

// Если ANSI, вызываем strrev, а если Unicode. - _wcsrev.

_tcsrev(g_szNumber);

/* */

if (fSyncChecked) {

// Если пользователь хочет синхронизировать потоки.

LeaveCriticalSection(&g_CriticalSection);

}

// Если пользователь - после каждой итерации хочет видеть на экране значение Cntr:

if (IsDlgButtonChecked(g_hwndDlg, IDC_SHOWCNTRTHRD))

AddToListBox(__TEXT("Cntr: Increment"));

}

return; //

//////////////////////////////////////////////////////////////////

// Поток, который добавляет текущее значение счетчика (собственно данные) в окно списка

void DisplayThread (LPVOID lpThreadParameter) {

BOOL fSyncChecked;

TCHAR szBuffer[50];

for (;; ){

// Определяем: нужна ли синхронизация потоков

fSyncChecked = IsDlgButtonChecked(g_hwndDlg, IDC_SYNCHRONIZE);

if (fSyncChecked)

EnterCriticalSection(&g_CriticalSection);

// Формируем строку с символьным представлением числа

_stprintf(szBuffer, __TEXT("Dspy: %d"), g_szNumber);

if (fSyncChecked)

LeaveCriticalSection(&g_CriticalSection);

// Добавляем строку в окно списка

AddToListBox(szBuffer);

}

return;

}

//////////////////////////////////////////////////////////////////

BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,

LPARAM lParam) {

HWND hWndCtl;

DWORD dwThreadID;

// Запоминание описателя диалогового окна в глобальной переменной, чтобы потоки могли

// легко получить к ней доступ. (Это необходимо сделать до создания потоков.)

g_hwndDlg = hwnd;

// Связываем значок с диалоговым окном

SetClassLong(hwnd, GCL_HICON, (LONG)

LoadIcon((HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),

__TEXT("CritSecs")));

// Инициализация критического раздела. Это нужно сделать до того, как к нему попытается

// обратиться какой-нибудь поток.