Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Метод рекомендации АЯ 2 семестр2.docx
Скачиваний:
113
Добавлен:
23.03.2016
Размер:
1.14 Mб
Скачать

3. Семафор

Работает по аналогии с взаимным исключением, только доступ к объекту может получить не один поток, а их число определяется параметром MaximumCount (при занятии потоком семафора текущее значение счетчика уменьшается на 1, семафор полностью занят, если значение счетчика равно 0)

HANDLE CreateSemaphore( // Создать семафор

LPSECURITY_ATTRIBUTES lpAttr, // Атрибуты доступа

LONG InitialCount, // Начальное значение семафора

LONG MaximumCount, // Макс. значение

LPCTSTR lpName ); // Имя семафора

Возможная схема использования:

WaitForSingleObject(HSem, // Занять семафор

INFINITE); // ждите сколько нужно

Count++; // Работа с синхронизированным объектом

ReleaseSemaphore(HSem, 1, 0); // Освободить одно место семафора

4. Событие

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

HANDLE hEvent;

hEvent=CreateEvent(0, // Создать объект - событие

false, // TRUE событие со сбросом вручную FALSE — событие с автосбросом

false, // свободное (TRUE) занятое (FALSE).

0);

WaitForSingleObject(hEvent,

INFINITE); // Программа далее не выполняется

Когда событие произошло необходимо вызвать в другом потоке функцию

SetEvent(hEvent);

6.2.4. Синхронизация процессов

С помощью объектов синхронизации можно организовать синхронизацию различных процессов. Например, доступ к объекту синхронизации, созданному в одном процессе (приложении), можно получить в другом приложении с помощью вызова функции OpenОбъект (Вместо термина объект идет имя объекта синхронизации). Например, для объекта «Событие» вызов имеет вид:

HANDLE OpenEvent(

DWORD dwDesiredAccess, // флаги доступа

BOOL bInheritHandle, // режим наследования

LPCTSTR lpName // имя события

);

Возможные значения флагов доступа:

  • EVENT_ALL_ACCESS

  • EVENT_MODIFY_STATE

  • SYNCHRONIZE

6.2.6. Создание потока в Си++ с помощью стандартной библиотеки C++

Поддержка многопоточности в языке Си++ определена стандартом 2011 г. [5], до этого приходилось использовать платформенно-зависимые средства, как представлено выше. В продуктах компании Microsoft можно пользоваться стандартными средствами библиотеки Си++ для создания потоков, начиная с версии Microsoft Visual C++ 2011. Для создания потока необходимо использовать класс thread [5], входящий в пространство имен std. Ниже представлен листинг программы с комментариями. Программа создана как консольное приложение. В программе в главном потоке (функция main) создаются два дочерних потока, в потоковую функцию в качестве параметра передается строка текста (объект класса string), это строка печатается 10 раз.

// stdafx.h: включаемый файл для стандартных системных включаемых файлов

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

// не часто изменяются

//

#pragma once

#include "targetver.h"

#include <stdio.h>

#include <tchar.h>

// TODO: Установите здесь ссылки на дополнительные заголовки, требующиеся для программы

#include <string>

#include <iostream>

#include <thread>

using namespace std;

// Thread1.cpp: определяет точку входа для консольного приложения.

//

#include "stdafx.h"

void myfun(string str) // Потоковая функция может иметь параметры при необходимости

{

for (int i = 0; i < 10; i++) // 10 раз печатаем строку

cout << endl << str.data();

}

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

{

thread th1(myfun, "Java"), th2(myfun, "C++");

// Создаем 2 объекта, первый параметр конструктора- указатель на потоковую функцию,

// следующие параметры передаются в потоковую функцию при необходимости

th1.join(); // Ждем завершение дочернего потока

th2.join(); // Ждем завершение дочернего потока

system("pause"); // Останавливаем программу до нажатия любой клавиши

return 0;

}

Результаты работы программы представлены на рисунке 4.

Рисунок 4 – Результаты работы многопоточной программы

На рисунке 4 в некоторых случаях виден беспорядочный вывод (каждая строка должна печататься с новой строчки, это правило иногда нарушено), что связано с отсутствием синхронизации (два потока работают одновременно с одним объектом cout).

Для синхронизации можно использовать объект класса mutex [5]. Ниже представлена программа с синхронизацией при печати.

// stdafx.h: включаемый файл для стандартных системных включаемых файлов

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

// не часто изменяются

//

#pragma once

#include "targetver.h"

#include <stdio.h>

#include <tchar.h>

// TODO: Установите здесь ссылки на дополнительные заголовки, требующиеся для программы

#include <string>

#include <iostream>

#include <thread>

#include <mutex>

using namespace std;

// Thread1.cpp: определяет точку входа для консольного приложения.

//

#include "stdafx.h"

mutex mut; // Создаем объект для синхронизации

void myfun(string str) // Потоковая функция может иметь параметры при необходимости

{

for (int i = 0; i < 10; i++) // 10 раз печатаем строку

{

mut.lock(); // Блокируем объект

cout << endl << str.data();

mut.unlock(); // Снимаем блокировку

}

}

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

{

thread th1(myfun, "Java"), th2(myfun, "C++");

// Создаем 2 объекта, первый параметр конструктора- указатель на потоковую функцию,

// следующие параметры передаются в потоковую функцию при необходимости

th1.join(); // Ждем завершение дочернего потока

th2.join(); // Ждем завершение дочернего потока

system("pause"); // Останавливаем программу до нажатия любой клавиши

return 0;

}

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

Рисунок 5 – Результаты работы многопоточной программы с синхронизацией