Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СПО_ЛАБ_3__15.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
126 Кб
Скачать

Функция WaitForSingleObject

Ждет, пока указанный объект находится в сигнальном состоянии или времени ожидания истекло.

Для ввода извещающие состояние ожидания, используйте WaitForSingleObjectEx функцию. Ждать несколько объектов, использовать WaitForMultipleObjects .

DWORD WINAPI WaitForSingleObject (

_In_ HANDLE hHandle,

_In_ DWORD dwMilliseconds);

Параметры hHandle 

Дескриптор объекта. Для получения списка типов объектов, чьи ручки могут быть указаны, см. следующий раздел Замечаний.

Если это ручка закрыт в то время как ожидание еще не принято, поведение функции является неопределенным.

Ручка должна иметь право доступа SYNCHRONIZE. Для получения дополнительной информации см. прав Стандартный доступа .

dwMilliseconds.

Интервал ожидания в миллисекундах. Если указано ненулевое значение, функция ждет, пока объект не получает сигнал или истекло. Если dwMilliseconds равна нулю, то функция не входит в состояние ожидания, если объект не сигнализируется; она всегда возвращает немедленно. Если dwMillisecondsбесконечно, то функция вернет только тогда, когда объект получает сигнал.

Примечание Значение dwMilliseconds не включает время, проведенное в маломощных государств.Например, время ожидания не будет держать отсчет, когда компьютер спит.

Возвращаемое значение

Функция list

По своей структуре списки сильно отличаются от векторов и деков(двусторонняя очередь), хотя они поддерживают почти весь набор операций характерных для деков и векторов, кроме того в списках есть набор специфических функций, каких именно, рассмотрим далее. Чтобы воспользоваться контейнером списков в С++, вам необходимо подключить следующий заголовочный файл:

#include <list>

Функция time.h

Заголовочный файл стандартной библиотеки языка программирования СИ, содержащий типы и функции для работы с датой и временем.

#include<time.h> 

Функция assert

Макрос assert(), определенный в заголовке <assert.h>, записывает информацию об ошибке в поток stderr, а затем прекращает выполнение программы, если выражение ехр равно нулю. В противном случае макрос assert() никаких действий не выполняет.

#include <assert.h>

В примере задержка выполнения программы будет вызвана только скоростью переключения потоков и их приоритетом. Кроме того, мы получили настоящую атомарность при изменении флагов. ОС гарантирует, что события (Event) меняются атомарно.

Пример 2. Пример с использованием Mutex, в котором два потока заполняют очередь.

#include "stdafx.h"

#include <windows.h>

#include <iostream>

#include <fstream>

#include <iomanip>

#include <stdlib.h>

#include <string>

#include <conio.h>

#include <stdio.h>

#include <list>

#include <time.h>

#include <assert.h>

#include <queue>

using namespace std;

typedef time_t;

HANDLE hMutex;

std::list<int> lstQueue;

double dtime;

queue<double> myQueue1;

queue<double> myQueue2;

time_t start;

time_t end;

DWORD WINAPI ThreadProc_1(PVOID pParam)

{

int val = *reinterpret_cast<int*>(pParam);

int Time =100;

for(int i =0; i < 10; i++)

{

WaitForSingleObject(hMutex, INFINITE);

lstQueue.push_back(val);

time_t start = time(NULL);

assert(start != (time_t)(-1));//vot

ReleaseMutex(hMutex);

int T=rand()*Time/(RAND_MAX+1);//расчет текущего времени ожидания

Sleep(100*T); //Просто задержка для наглядности работы

time_t end = time(NULL);

//Возвращает текущее календарное время или −1, если это время не известно. Если указатель tp не равен NULL, то возвращаемое значение записывается также и в *tp

assert(end != (time_t)(-1));//vot

dtime = difftime(end,start);

//void queue::qinsert(double dtime);

myQueue1.push(dtime);

cout<<" step = "<<i<<" T 1 = "<<T<<" dtime = "<<dtime<<endl;

}

return 0;

}

DWORD WINAPI ThreadProc_2(PVOID pParam)

{

int val = *reinterpret_cast<int*>(pParam);

int Time =50;

for(int i =0; i < 10; i++)

{

WaitForSingleObject(hMutex, INFINITE);

lstQueue.push_back(val);

time_t start = time(NULL);

assert(start != (time_t)(-1));//vot

ReleaseMutex(hMutex);

int T=rand()*Time/(RAND_MAX+1);//расчет текущего времени ожидания

Sleep(100*T); //Просто задержка для наглядности работы

time_t end = time(NULL);

//Возвращает текущее календарное время или −1, если это время не известно. Если указатель tp не равен NULL, то возвращаемое значение записывается также и в *tp

assert(end != (time_t)(-1));//vot

dtime = difftime(end,start);

myQueue2.push(dtime);

cout<<" step = "<<i<<" T 2 = "<<T<<" dtime = "<<dtime<<endl;

}

return 0;

}

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

{

//Создаем объекты синхронизации

hMutex = CreateMutex(NULL, FALSE, NULL);

//запускаем поток

DWORD dwID;

int iVal1 = 1, iVal2 = 2;

//Начинаем заполнять очередь.

HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc_1, &iVal1, 0, &dwID);

HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc_2, &iVal2, 0, &dwID);

//Ждем завершеня потоков

HANDLE hEvents[2] = {hThread1, hThread2};

WaitForMultipleObjects(2, hEvents, TRUE, INFINITE);

//Печать результата

int mumber1 = myQueue1.size();

int mumber2 = myQueue2.size();

for(int kk = 0; kk < mumber1; ++kk){

cout << kk<<"Element"<<" myQueue1 = "<<myQueue1.front()<<endl;

myQueue1.pop();

}

cout << "------------------------"<<endl;

for(int kkk = 0; kkk < mumber2; ++kkk){

cout << kkk<<"Element"<<" myQueue2 = "<<myQueue2.front()<<endl;

myQueue2.pop();

}

//for(std::list<int>::iterator it = lstQueue.begin(); it != lstQueue.end(); it++)

//{

// std::cout <<" *it = "<< *it <<" dtime = "<<dtime<< ", "<<endl; //печатаем результат

//}

CloseHandle(hThread1);

CloseHandle(hThread2);

CloseHandle(hMutex);

system("pause");//запрос на завершение работы приложения

return 0;

}

Несмотря на то, что добавление нового элемента в список - это всего одна строка, это комплексная операция. Она содержит помимо всего прочего и операции распределения памяти. Поэтому синхронизация доступа к списку обязательна.

Задания:

1.Рассмотреть вариант данного примера без синхронизации.

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

Пример 3. Рассмотрим пример, в котором главный поток программы готовит данные и устанавливает некий признак готовности. После чего он дожидается обработки данных. Причем он может в это время выполнять какие-либо другие действия.

#include "stdafx.h"

#include <windows.h>

#include <iostream>

#include <fstream>

#include <iomanip>

#include <stdlib.h>

#include <string>

#include <conio.h>

#include <stdio.h>

using namespace std;

HANDLE hReadyForProcessing;

HANDLE hDataReady;

HANDLE hTerminate;

int iResult = 0;

DWORD WINAPI ThreadProc(PVOID pPararn)

{

HANDLE hEvents[2] = {hReadyForProcessing, hTerminate};

DWORD dwRes;

while(WAIT_OBJECT_0 + 0 == (dwRes = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE)) )

{

iResult = iResult * 10;

SetEvent(hDataReady);

}

if(WAIT_OBJECT_0 + 1 != dwRes) //Условие завершения

{

return 2;//Что то не так с вызовом WaitForMultipleObjects

}

return 0;

}

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

{

//Создаем объекты синхронизации

hReadyForProcessing = CreateEvent(NULL, FALSE, FALSE, NULL);

hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);

hTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);

//запускаем поток

DWORD dwID;

HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwID);

for(int i = 0; i < 100; i++)

{

iResult = 10*(i+1);

SetEvent(hReadyForProcessing); //указываем потоку, что есть данные для обработки

WaitForSingleObject(hDataReady, INFINITE);

/*

if(10000 != iResult)

{

std::cout << "error" << std::endl;

}

*/

std::cout <<" i="<<i<<" iResult = "<< iResult << std::endl; //печатаем результат

}

SetEvent(hTerminate); //запрос на завершение потока

if(WAIT_OBJECT_0 != WaitForSingleObject(hThread, 5000))

{

TerminateThread(hThread, 3);

std::cout << "Error in thread" << std::endl;

}else

{

CloseHandle(hThread);

}

CloseHandle(hDataReady);

CloseHandle(hReadyForProcessing);

CloseHandle(hTerminate);

system("pause");//запрос на завершение работы приложения

return 0;

}

В примере задержка выполнения программы будет вызвана только скоростью переключения потоков и их приоритетом. Кроме того, мы получили настоящую атомарность при изменении флагов. ОС гарантирует, что события (Event) меняются атомарно.

Задания:

1.В функции ThreadProc установить случайное увеличение параметра и iResult.

2. Увеличить количество потоков с одного до двух.

Использование семафора при помощи API-функций

Семафор представляет собой глобальный объект, позволяющий синхронизировать работу двух или нескольких процессов или потоков. Для программиста семафор - это просто счетчик. Если счетчик равен N, это означает, что к ресурсу имеют доступ N процессов. Рассмотрим функции для работы с семафорами.

CreateSemaphor - создаёт глобальный объект-семафор. Возвращает дескриптор семафора.

HANDLE CreateSemaphore

(

LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

LONG lInitialCount,

LONG lMaximumCount,

LPCTSTR lpName)

Первый параметр - указатель на структуру, определяющую атрибуты доступа. Может иметь значение для Windows NT. Обычно данный параметр равен NULL. Второй параметр - начальное значение счётчика семафора. Определяет, сколько задач имеют доступ к ресурсу в начале. Третий параметр - количество задач, которые имеют одновременный доступ к ресурсу. Четвёртый параметр - указатель на строку, содержащую имя семафора.

OpenSemaphor - открыть уже созданный семафор. Возвращает дескриптор семафора. Данную функцию используют не так часто. Обычно создают семафор и присваивают его дескриптор глобальной переменной, а потом используют этот дескриптор в порождаемых потоках.

HANDLE OpenSemaphore

(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

LPCTSTR lpName)

Параметры функции: первый параметр - определяет желаемый уровень доступа к семафору. Возможны значения:

-SEMAPHORE_MODiFY_STATE = 2H, разрешить использование функции ReleaseSemaphore,

- SYNCHRONIZE = 100000H, разрешить использование любой функции ожидания, только для Windows NT,

- SEMAPHORE_ALLACCESS = 0F0000h+ SYNCHRONIZE+3H, специфицирует все возможные флаги доступа к семафору.

Для контроля ожидания открытия семафора используется функция WaitForSingleObject.

DWORD WaitForSingleObject

(

HANDLE hHandle,

DWORD dwMilliseconds

)

Первый параметр – дескриптор семафора. Второй параметр – время ожидания в миллисекундах. Если параметр равен INFINITE = 0FFFFFFFFh, то время ожидания не ограничено.

При успешном завершении, т. е. открытии доступа к объекту, функция возвращает 0. Значение 102h будет означать, что заданный период ожидания не завершен.

ReleaseSemaphore – функция освобождения семафора, которая позволяет получить доступ к ресурсу другим процессам.

BOOL ReleaseSemaphore

(

HANDLE hSemaphore,

LONG lReleaseCount,

LPLONG lpPreviousCount

)

Первый параметр – дескриптор семафора. Второй параметр – определяет какое значение должно быть добавлено к счетчику семафора. Чаще всего этот параметр равен единице. Третий параметр – указатель на переменную, куда должно быть перемещено предыдущее значение счетчика.

Рассмотрим алгоритм работы с семафором. Сначала при помощи функции CreateSemaphore создадим семафор, его дескриптор присваивается глобальной переменной. Перед попыткой обращения к ресурсам доступ, к которым необходимо ограничить, поток должен вызвать функцию WaitForSingleObject. При открытии доступа функция возвращает 0. По окончании работы с ресурсом следует вызвать функцию ReleaseSemaphor. Тем самым увеличивается счётчик доступа на 1. С помощью семафора можно регулировать количество потоков, которые одновременно могут иметь доступ к ресурсу. Максимальное значение счетчика как раз и определяет, сколько потоков могут получить доступ к ресурсу одновременно. Но обычно, как мы уже говорили, максимальное значение полагают равным 1.

Пример 4

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

//

#include "stdafx.h"

#include <windows.h>

#include <iostream>

#include <fstream>

#include <iomanip>

#include <stdlib.h>

#include <string>

#include <conio.h>

#include <stdio.h>

#include <list>

#include <time.h>

#include <assert.h>

#include <queue>

#include "process.h" // vot ito

#include <math.h>

using namespace std;

HANDLE hSemaphore;

LONG cMax = 2;

void Test1(void *);

void Test2(void *);

void Test3(void *);

void main()

{

hSemaphore = CreateSemaphore(

NULL,// нет атрибута

cMax,// начальное состояние

cMax,// максимальное состояние

NULL// без имени

);

if (!hSemaphore == NULL)

{

if (_beginthread(Test1,1024,NULL)==-1)

cout << "Error begin thread " << endl;

if (_beginthread(Test2,1024,NULL)==-1)

cout << "Error begin thread " << endl;

if (_beginthread(Test3,1024,NULL)==-1)

cout << "Error begin thread " << endl;

Sleep(10000);

CloseHandle(hSemaphore);

}

else

cout << "error create semaphore" << endl;

system("pause");//запрос на завершение работы приложения

}

void Test1(void *)

{

cout << "Test1 Running\n" << endl;

DWORD dwWaitResult=1;

while(dwWaitResult!=WAIT_OBJECT_0)

{

dwWaitResult = WaitForSingleObject(

hSemaphore,// указатель на семафор

1// интерфал ожидания

);

cout << "Test 1 TIMEOUT\n" << endl;

}

Sleep(1000);

if (ReleaseSemaphore(

hSemaphore,// указатель на светофор

1,// изменяет счетчик на 1

NULL)

)

cout << " ReleaseSemaphore Ok Test1\n" << endl;

_endthread();

}

void Test2(void *)

{

cout << "Test2 Running\n" << endl;

DWORD dwWaitResult=1;

while(dwWaitResult!=WAIT_OBJECT_0)

{

dwWaitResult = WaitForSingleObject(hSemaphore,1);

cout << "Test 2 TIMEOUT\n" << endl;

}

Sleep(1000);

if (ReleaseSemaphore(hSemaphore,1,NULL))

cout << " ReleaseSemaphore Ok Test2\n" << endl;

_endthread();

}

void Test3(void *)

{

cout << "Test3 Running\n" << endl;

DWORD dwWaitResult=1;

while(dwWaitResult!=WAIT_OBJECT_0)

{

dwWaitResult = WaitForSingleObject(hSemaphore,1);

cout << "Test 3 TIMEOUT\n" << endl;

}

if (ReleaseSemaphore(hSemaphore,1,NULL))

cout << " ReleaseSemaphore Ok Test3\n" << endl;

_endthread();

}

void Test2(void *)

{

cout << "Test2 Running\n" << endl;

DWORD dwWaitResult;

while(dwWaitResult!=WAIT_OBJECT_0)

{

dwWaitResult = WaitForSingleObject(hSemaphore,1);

cout << "Test 2 TIMEOUT\n" << endl;

}

Sleep(1000);

if (ReleaseSemaphore(hSemaphore,1,NULL))

cout << " ReleaseSemaphore Ok Test2\n" << endl;

_endthread();

}

void Test3(void *)

{

cout << "Test2 Running\n" << endl;

DWORD dwWaitResult;

while(dwWaitResult!=WAIT_OBJECT_0)

{

dwWaitResult = WaitForSingleObject(hSemaphore,1);

cout << "Test 3 TIMEOUT\n" << endl;

}

if (ReleaseSemaphore(hSemaphore,1,NULL))

cout << " ReleaseSemaphore Ok Test3\n" << endl;

_endthread();

system("pause");//запрос на завершение работы приложения

}