Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.04.2008, 14:14   #11
MaTBeu
Eclipse Foundation
Старожил
 
Аватар для MaTBeu
 
Регистрация: 19.09.2007
Сообщений: 2,604
По умолчанию

Спасибо за информацию! Будем разбираться А насчет примера, я думаю, если у меня возникнут сложности при написании программы, я обращусь к Вам.
MaTBeu вне форума Ответить с цитированием
Старый 23.05.2008, 21:31   #12
MaTBeu
Eclipse Foundation
Старожил
 
Аватар для MaTBeu
 
Регистрация: 19.09.2007
Сообщений: 2,604
По умолчанию Ступор :(

Многопоточные приложения Дубль 2
Здравствуйте. У меня вот возник вопрос. Он возможно сликом ламерский, но я действительно в ступоре. Есть схема синхронизации под названием Read/Write Lock. Но... есть одно "но", и это "но" не дает мне покоя. Где в данном примере потоки? Я просто не знаю с чем работать и как эти потоки создавать. Помогите разобраться, код ниже.
Код:
#include <windows.h>
#include <assert.h>
#include <string.h>


class CRWLock
{
protected:
	HANDLE					hExitEvent;
	CRITICAL_SECTION		cs;
	DWORD volatile			hExclusiveOwner;
	long volatile			nReaders;
	long volatile			nExclusiveRecursion;
public:
	CRWLock()
	{
		this->hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		InitializeCriticalSection(&this->cs);
		this->nReaders = 0;
		this->hExclusiveOwner = NULL;
		this->nExclusiveRecursion = 0;

		assert(this->hExitEvent);
	};
	~CRWLock()
	{
		CloseHandle(this->hExitEvent);
		DeleteCriticalSection(&this->cs);
	};
	void AcquireLockShared()
	{
		// Здесь пытаемся получить право на чтение
		// Ждём входа в критическую секцию и, как только попадаем в неё,
		// увеличиваем счётчик "читателей" и сразу же выходим из критической секции.

		EnterCriticalSection(&this->cs);
		this->nReaders ++;
		LeaveCriticalSection(&this->cs);
	};
	void AcquireLockExclusive()
	{
		// Здесь пытаемся получить уже право на запись
		// Аналогично ждём критическую секцию

		EnterCriticalSection(&this->cs);

		// Но уже не покидаем её сразу же, а, во-первых, увеличиваем счётчик 

рекурсивных
		// входов в критичекую секцию, (на тот случай, если Мы уже вошли в в неё в 

этом же 
		// потоке) и, во-вторых, если это первый вход потока в критическую секцию, 

ждём
		// когда с данными закончат работать все читающие потоки - проверяем 

количество 
		// читателей и, если они присутствуют, ждём сигнала о выходе очередного 

читателя 
		// из режима чтения. Новые "читатели" получить доступ пока не смогут - 

критическую 
		// секцию мы заняли.

		this->nExclusiveRecursion ++;
		if(this->hExclusiveOwner != GetCurrentThreadId())
		{
			// Будем ждать, когда "выйдут" все "читатели" только если уже не 

владеем защёлкой
			// иначе это уже было выполнено раньше.

			this->hExclusiveOwner = GetCurrentThreadId();

			while(this->nReaders > 0)
			{
				// Ждём сигнала о выходе очередного читателя
				WaitForSingleObject(this->hExitEvent, INFINITE);
			}
		}
	}
	void ReleaseLock()
	{
		// А здесь освобождаем нашу защелку.
		if(this->hExclusiveOwner == GetCurrentThreadId())
		{
			// Если мы выходим из эксклюзивного режима, то уменьшаем число 

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

владельца в NULL
			this->nExclusiveRecursion --;
			if(0 == this->nExclusiveRecursion)
			{
				this->hExclusiveOwner = NULL;
			}

			// и только теперь "отпускаем" критическую секцию. Число входов в неё 

должно 
			// быть равно числу выходов, так что в случае рекрсивного входа, 

раньше времени 
			// она не освободится.
			LeaveCriticalSection(&this->cs);
		}
		else
		{
			// Если же мы - "читатель", то просто уменьшаем количество 

"читателей" (поскольку
			// мы, являясь читателем, уже вышли из критической секции, ещё в 

AcquireLockShared, 
			// то вынуждены во избежание проблем делать это атомарно - через 

InterlockedDecrement.
			
			InterlockedDecrement(&this->nReaders);
			
			

			SetEvent(this->hExitEvent);
		}
	}
};
В msdn я читал о потоках... Но... там такие яркие примеры, что я в них понял чуть меньше, чем ничего.
MaTBeu вне форума Ответить с цитированием
Старый 23.05.2008, 22:18   #13
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

MaTBeu, потоки создаются элементарно:
Код:
#include <windows.h>
#include <stdio.h>

typedef struct _THREAD_PARAM
{
	DWORD dwParam;
	//........................
	//........................
}THREAD_PARAM, *LPTHREAD_PARAM;


//Функция первого потока
DWORD WINAPI Thread1(LPTHREAD_PARAM lpParameter)
{
	printf("Thread 1 reporting: Execution started, parameter=%d\n", lpParameter->dwParam);
	// Некий код потока
	Sleep(8000);
	puts("Thread 1 reporting: Work done.");
	return 0;
}

//Функция второго потока
DWORD WINAPI Thread2(LPTHREAD_PARAM lpParameter)
{
	printf("Thread 2 reporting: Execution started, parameter=%d\n", lpParameter->dwParam);
	// Некий код потока
	Sleep(3000);
	puts("Thread 2 reporting: Work done.");
	return 0;
}

//Функция третьего потока
DWORD WINAPI Thread3(LPTHREAD_PARAM lpParameter)
{
	printf("Thread 3 reporting: Execution started, parameter=%d\n", lpParameter->dwParam);
	// Некий код потока
	Sleep(5000);
	puts("Thread 3 reporting: Work done.");
	return 0;
}

int main()
{
	HANDLE			hThreads[3];
	THREAD_PARAM	Params[3];

	// Запускаем первый поток
	Params[0].dwParam = 100;
	hThreads [0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread1, &Params[0], 0, NULL);
	puts("main reporting: Thread 1 created");

	// Запускаем второй поток
	Params[1].dwParam = 200;
	hThreads [1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread2, &Params[1], 0, NULL);
	puts("main reporting: Thread 2 created");

	// Запускаем третий поток
	Params[2].dwParam = 300;
	hThreads [2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread3, &Params[2], 0, NULL);
	puts("main reporting: Thread 3 created");

	// И теперь ждём, когда они все завершатся
	puts("Waiting for threads....");
	WaitForMultipleObjects(3, hThreads, TRUE, INFINITE);

	puts("main reporting: done");
	getchar();
	return 0;
}
B_N вне форума Ответить с цитированием
Старый 23.05.2008, 22:54   #14
MaTBeu
Eclipse Foundation
Старожил
 
Аватар для MaTBeu
 
Регистрация: 19.09.2007
Сообщений: 2,604
По умолчанию

Спасибо на этом. Немного разобрался. А если вот создавать класс UserThread, к примеру, то какие, помимо DWORD dwParam;, поля должны у него присутствовать? Или есть уже готовый класс Thread и его можно унаследовать?
MaTBeu вне форума Ответить с цитированием
Старый 23.05.2008, 23:07   #15
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Цитата:
Сообщение от MaTBeu Посмотреть сообщение
..........какие, помимо DWORD dwParam;, поля должны у него присутствовать? Или есть уже готовый класс Thread и его можно унаследовать?
Да какие угодно, хоть большую советскую энциклопедию. Функция потока может принять один параметр, а уж что туда передавать зависит от нашей фантазии, как правило, это указатель на что-нибудь. А насчёт классов - можно конечно. Только не помню, на Борланде Вы творите, или на MS. Реализации классов потоков у них довольно сильно отличаются, к тому жеу Борланда она какая-то дурацкая, лучше не скажешь. В принципе, этот единственный параметр позволяет замечательно передавать в поток указатель this. Вот здесь я приводил такой вариант на дельфи.
B_N вне форума Ответить с цитированием
Старый 23.05.2008, 23:34   #16
MaTBeu
Eclipse Foundation
Старожил
 
Аватар для MaTBeu
 
Регистрация: 19.09.2007
Сообщений: 2,604
По умолчанию

Я, как Вы выражаетесь "творю" на MSVS 2008 TS Кстати о том примере на Делфи... Короче о создании потоков я понял (это наверное, единственное, что я понял из кода на Делфи, потому как Делфи никогда не учил). Но в целом задумка мне понятна.

ПС: еще один вопрос. Чтобы связать Вашу схему синхронизации с массивом потоков, к примеру, которые представляют также отдельный класс, нужно просто создать обьект класса CRWLock, а потоки сами к нему привяжутся? Просто вызывать методы этого класса, когда нужно и все?
MaTBeu вне форума Ответить с цитированием
Старый 23.05.2008, 23:57   #17
B_N
Новичок
Джуниор
 
Регистрация: 18.01.2008
Сообщений: 1,720
По умолчанию

Цитата:
Сообщение от MaTBeu Посмотреть сообщение
Чтобы связать Вашу схему синхронизации с массивом потоков, к примеру, которые представляют также отдельный класс, нужно просто создать обьект класса CRWLock, а потоки сами к нему привяжутся? Просто вызывать методы этого класса, когда нужно и все?
Ну в принципе - да. Объявляете какой-то глобальный объект данных, к которому привязываете этот Lock, а потом в любом потоке можете читать/писать эти данные - получаете соттветствующий доступ через AcquireLockExclusive/AcquireLockShared, пишете/читаете и отпускаете после этого защелку через ReleaseLock.
B_N вне форума Ответить с цитированием
Старый 24.05.2008, 20:37   #18
MaTBeu
Eclipse Foundation
Старожил
 
Аватар для MaTBeu
 
Регистрация: 19.09.2007
Сообщений: 2,604
По умолчанию

Премного благодарен. На этом мои вопросы ПОКА исчерпаны
MaTBeu вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
MDI приложения и PageControl.... maLoy*508 Общие вопросы Delphi 2 04.04.2008 02:28
Делаю сайты, пишу маленькие/большие скрипты. Пишу веб-приложения и приложения под Windows. SkyM@n Фриланс 3 29.12.2007 16:21
Приложения в XP vicvtor Win Api 9 31.08.2007 22:55
создание приложения MarinaSt Общие вопросы Delphi 8 04.07.2007 23:51
Иконка приложения Баламут Общие вопросы Delphi 9 05.06.2007 20:14