• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

синхронизация семафором

  • Автор темы Guest
  • Дата начала
G

Guest

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

C++:
// при нажатии "1,2…9" -> F=F+1,2…9 (операция 1)
// при нажатии "Alt+1,2…9" -> F=F-1,2…9 (операция 2)

#include <windows.h>
#include <conio.h>
#include <iostream.h>
#include <time.h>
HANDLE hThread; //дискриптор создаваемого потока 
DWORD IDThread; //идентификатор потока
int F=0; //разделяемая глобальная переменная
clock_t wtime=100; //время задержки(мс)
void waiting(clock_t dt); //функция задержки
struct log {
int nom; //порядковый номер операции
int key; //код нажатой клавиши
DWORD ID; //идентификатор созданного потока
clock_t t1; //время начала операции
clock_t t2; // время завершения операции
int F; //результат операций в дочернем потоке
int Fc; //результат операций в главном потоке

} mylog[1000]; //неболее 1000 операций
DWORD ThreadProc1(log *p); //функция потока 1 (параметр - pointer на структуру log)
DWORD ThreadProc2(log *p); //функция потока 2 (параметр - pointer на структуру log)
//=================================== ==============
int main() //главный поток
{
int i=0; //счётчик операций
int j=1; //счётчик вывода строк журнала
int key=1; //код нажатой клавиши
int flag=1; //признак завершения программы
int Fcontr; //переменная-дублёр
mylog[1].t2=0; //признак того,что поток не завершён
Fcontr=F;

//Повторять пока flag!=0 или i<1000
while (flag || i >=1000)
{
//Приём кода нажатой клавиши
if (kbhit()!= 0)
{
key= getch();
if (key==0) key=getch();

//Формирование переменной дублёра
if ((key>=49) && (key<=57))
Fcontr=Fcontr+key-48;
else if ((key>=120) && (key<=128))
Fcontr=Fcontr-key+119;
if (key==27)
{
flag=0;
break;
}
//Формируем строку журнала 
i++;
mylog[i].nom=i;
mylog[i].key=key;
mylog[i].t2=0;
mylog[i].F=0;
mylog[i].Fc=Fcontr;
mylog[i].t1=clock();
//Создание потока 1 без немедленного запуска
if ((key>=49) && (key<=57))
{
hThread= CreateThread(NULL,0,ThreadProc1,&my log[i],CREATE_SUSPENDED,&IDThread);
}
if ((key>=120) && (key<=128))
{
hThread= CreateThread(NULL,0,ThreadProc2,&my log[i],CREATE_SUSPENDED,&IDThread);
}
//Проверяем создался ли поток
if (hThread == NULL)
{ cout << "Thread error" << key << endl;
getch();
return 0;
}
else
{
mylog[i].ID=IDThread;
ResumeThread(hThread);
}
}
//Завершение работы потока проверяется по сформированному в функции потока значению времени t2
if (mylog [j].t2!=0)
{
//вывод j-той строки журнала
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc <<endl;
j=++j; //следующая строка журнала
}
} //Повторять пока flag!=0 или i<1000
getch();
return 0;
}

//Функция потока:имитация ”чтения”корректировки
//и ”записи” разделяемой переменной F
//параметр-указатель на текущую строку журнала
DWORD ThreadProc1(log *p)
{
int Fbuf;
//чтение разделяемой переменной в буферную переменную
Fbuf=F;
waiting(wtime); //задержка
//корректировка буферной переменной
if (((*p).key >= 49)&&((*p).key <= 57))
Fbuf=Fbuf+p->key-48;
waiting(wtime);//задержка
//запись из буферной переменной в разделяемую переменную
F=Fbuf;
//запись результата в текущую строку журнала
(*p).F=F;
(*p).t2=clock(); //время окончания работы потока
return 0;
}

DWORD ThreadProc2(log *p)
{
int Fbuf;
//чтение разделяемой переменной в буферную
Fbuf=F;
waiting(wtime); //задержка
//корректировка буферной переменной
if (((*p).key >= 120)&&((*p).key <= 128))
Fbuf=Fbuf-p->key+119;
waiting(wtime);//задержка
//запись результата из буферной переменной в разделяемую
F=Fbuf;
//запись результата в текущую строку журнала
(*p).F=F;
(*p).t2=clock(); //время окончания работы потока
return 0;
}

//функция задержки
//параметр – время задержки в мс
void waiting(clock_t dt) {
clock_t tn;
tn=clock();
while (clock()-tn < dt);
return 0;
}
Добавлено: Пробовал написать вот так, но преподаватель сказал что с точки зрения логики это не правильно.

C++:
#include <windows.h>
#include <conio.h>
#include <iostream.h>
#include <time.h>
HANDLE hThread;
const char lpSemaphoreName[] = "MySemaphore";
HANDLE hSemaphore;
DWORD IDThread;
int F=0;
clock_t wtime=100;
void waiting(clock_t dt);
struct log {
int nom;
int key;
DWORD ID;
clock_t t1;
clock_t t2;
int F;
int Fc;

} mylog[1000];
DWORD ThreadProc1(log *p);
DWORD ThreadProc2(log *p);
//=================================== ==============
int main()
{

int i=0;
int j=1;
int key=1;
int flag=1;
int Fcontr;
mylog[1].t2=0;
Fcontr=F;
hSemaphore = CreateSemaphore(NULL, 0, 1, lpSemaphoreName);
if(hSemaphore == NULL) {
cout<<"Oshibka pri sozdanii semafora!"<<endl;
return 0;
}
while (flag || i >=1000)
{
if (kbhit()!= 0)
{
key= getch();
if (key==0) key=getch();
if ((key>=49) && (key<=57))
Fcontr=Fcontr+key-48;
else if ((key>=120) && (key<=128))
Fcontr=Fcontr-key+119;
if (key==27)
{
flag=0;
break;
}
i++;
mylog[i].nom=i;
mylog[i].key=key;
mylog[i].t2=0;
mylog[i].F=0;
mylog[i].Fc=Fcontr;
mylog[i].t1=clock();
if ((key>=49) && (key<=57))
{
hThread= CreateThread(NULL,0,ThreadProc1,&my log[i],0,&IDThread);
}
if ((key>=120) && (key<=128)){
hThread= CreateThread(NULL,0,ThreadProc2,&my log[i],CREATE_SUSPENDED,&IDThread);}
if (hThread == NULL)
{ cout << "Thread error" << key << endl;
getch();
return 0;
}
else
{
mylog[i].ID=IDThread;
ResumeThread(hThread);
}
WaitForSingleObject(hSemaphore, 30000)
}
if (mylog [j].t2!=0)
{
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc <<endl;
j=++j;
}
}
getch();
return 0;
}


DWORD ThreadProc1(log *p)
{
int Fbuf;
Fbuf=F;
waiting(wtime);
if (((*p).key >= 49)&&((*p).key <= 57))
Fbuf=Fbuf+p->key-48;
waiting(wtime);
if(hSemaphore != NULL)
ReleaseSemaphore(hSemaphore, 1, NULL);
F=Fbuf;
(*p).F=F;
(*p).t2=clock();
return 0;
}

DWORD ThreadProc2(log *p)
{
int Fbuf;
Fbuf=F;
waiting(wtime);
if (((*p).key >= 120)&&((*p).key <= 128))
Fbuf=Fbuf-p->key+119;
waiting(wtime);
if(hSemaphore != NULL)
ReleaseSemaphore(hSemaphore, 1, NULL);
F=Fbuf;
(*p).F=F;
(*p).t2=clock();
return 0;
}

void waiting(clock_t dt) {
clock_t tn;
tn=clock();
while (clock()-tn < dt);
return;
}

Заранее благодарю за помощь =)
 
L

lazybiz

Во-первых семафору можно не давать имени. Задачу это не решает но все же:
C++:
hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
Замени функцию
C++:
void waiting(clock_t dt)
на
C++:
Sleep( ms )
.
Да и упрости немного, приведи в порядок а то читать невозможно, ну и разобраться соответственно.
 
D

DarkKnight

Помогите синхронизировать потоки с помощью семафора.С++ с использованием стандартных функций CreateSemaphore(),ReleaseSemaphore( ) и тд.
Щас глянем...
Сразу встречный вопрос в чем именно писал? И каким компилятором компилировал?
А то сразу смотрю на имя структуры (log) - точно знаю MS VC - такое не прохавает
 
D

DarkKnight

C++:
Сначало по синтаксису пройдемся.... С++ конечно язык гибкий, но все же правил нужно же предерживаться:
1. Разрешение конфликта имен:
C++:
struct _log /* ПЕРЕИМЕНОВАЛ структуру, а то с функцией конфликтует */
{
int nom; //порядковый номер операции
int key; //код нажатой клавиши
DWORD ID; //идентификатор созданного потока
clock_t t1; //время начала операции
clock_t t2; // время завершения операции
int F; //результат операций в дочернем потоке
int Fc; //результат операций в главном потоке
} mylog[1000]; //неболее 1000 операций
2. Прототипы на функции и их определения (а имеено LPTHREAD_START_ROUTINE)
C++:
//DWORD ThreadProc1(_log*); //функция потока 1 (параметр - pointer на структуру log)
DWORD WINAPI ThreadProc1(LPVOID);/*В WIN-API Функция потока имеет имеено такой протатип */
DWORD WINAPI ThreadProc2(LPVOID); 
//DWORD ThreadProc2(_log*); //функция потока 2 (параметр - pointer на структуру log)
3. Не верные возвращаемые значения:
C++:
//функция задержки
//параметр – время задержки в мс
void waiting(clock_t dt) 
{
clock_t tn;
tn=clock();
while (clock()-tn < dt);
//return 0; /* Не подойдет */
return; /* В самый раз или вообще без него */
}
Это все что касается синтаксиса...
 
D

DarkKnight

Примерно что то вроде такого:
Ну синхронизаця точно работать будет....
а вот kbhit() - мне совсем не нравится....

C++:
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <time.h>
using namespace std; /*ДОБАВИЛ ДЛЯ std */

HANDLE hThread; //дискриптор создаваемого потока 
DWORD IDThread; //идентификатор потока
int F=0; //разделяемая глобальная переменная
clock_t wtime=100; //время задержки(мс)
HANDLE Semaphore; //Наш семафор

void waiting(clock_t dt); //функция задержки /*ВОТ ЭТО МЕСТНО - ВООБЩЕ ПОНРАВИЛОСЬ [+] */

struct _log /* ПЕРЕИМЕНОВАЛ структуру, а то с функцией конфликтует */
{
int nom; //порядковый номер операции
int key; //код нажатой клавиши
DWORD ID; //идентификатор созданного потока
clock_t t1; //время начала операции
clock_t t2; // время завершения операции
int F; //результат операций в дочернем потоке
int Fc; //результат операций в главном потоке
} mylog[1000]; //неболее 1000 операций

//DWORD ThreadProc1(_log*); //функция потока 1 (параметр - pointer на структуру log)
DWORD WINAPI ThreadProc1(LPVOID);/*В WIN-API Функция потока имеет имеено такой протатип */
DWORD WINAPI ThreadProc2(LPVOID); 
//DWORD ThreadProc2(_log*); //функция потока 2 (параметр - pointer на структуру log)

//=================================== ==============
int main() //главный поток
{
int i=0; //счётчик операций
int j=1; //счётчик вывода строк журнала
int key=1; //код нажатой клавиши
int flag=1; //признак завершения программы
int Fcontr; //переменная-дублёр
//mylog[1].t2=0; //признак того,что поток не завершён
Fcontr=F;
//Создадим 
Semaphore = CreateSemaphore(NULL,1,1,NULL);
//Повторять пока flag!=0 или i<1000
while (flag || i <=1000) /* Ну здесь вроде пока программа не завершится и i==1000*/
{
//Приём кода нажатой клавиши
if (kbhit()) /*Предположим что приняли */
{
/*ТУТ У ТЕБЯ НЕ САМАЯ ЛУЧШАЯ РЕАЛИЗАЦИЯ с kbhit() была
нужно примерно на такую исправить*/
key = getche();
//key= getchar(); 
//if (key==0) key=getch();
//Формирование переменной дублёра
if ((key>=49) && (key<=57)) /* Оно число*/
Fcontr=Fcontr+key-48; /* Увеличим некую переменную-дублер (пока еще не знаю что это правда) на цифру нажатой клавиши*/
else if ((key>=120) && (key<=128)) /* Как я понимаю если нажато что попало*/
Fcontr=Fcontr-key+119; /* То уменьшим странную переменную на что то */
if (key==27) /* Если ESC - то досвидание*/
{
flag=0;
break;
}
//Формируем строку журнала 
i++; /*Увеличим счетчик, сразу возникает вопрос, а что с первым элементом то mylog[0]? */
mylog[i].nom=i; /* Запишим номер будем считать его ID-уникальным индексом */
mylog[i].key=key; /* Клавишу */
mylog[i].t2=0; /* Обнулим время завершения*/
mylog[i].F=0;/*Рузультат в доч. потоке (это я пока что тоже не понимаю) */
mylog[i].Fc=Fcontr; /* Запишим результат в главном потоке, равеной чудо переменной-дублеру (я аж заинтригован) */
mylog[i].t1=clock(); /* Начало выполнение запишим */

//Создание потока 1 без немедленного запуска
if ((key>=49) && (key<=57)) /* Если клавиша все же циферная */
{
hThread= CreateThread(NULL,0,&ThreadProc1,&mylog[i],CREATE_SUSPENDED,&IDThread);/* Согласен*/
}
if ((key>=120) && (key<=128)) /* Если что попало, то*/
{
hThread= CreateThread(NULL,0,&ThreadProc2,&mylog[i],CREATE_SUSPENDED,&IDThread); /* То сделаем тоже самое, но ч другим потоком.. не помню точно,
что именно содержится в кодах от 120 до 128
и что точно отбрасывается от 58..119, но думаю какой то
определенный смысл в этом есть*/
}
//Проверяем создался ли поток
if (hThread == NULL) /* Согласен*/
{ 
cout << "Thread error" << key << endl;
getch();
return 0;
}
else
{
mylog[i].ID=IDThread; //Запишим в структуру IDпотока
ResumeThread(hThread); /*Запустим поток*/
}
}

/*А вот в этом месте уже не допонимаю*/
//Завершение работы потока проверяется по сформированному в функции потока значению времени t2

if (mylog[j].t2 != 0) /* Хм... Если у j-потока конечное время не равно 0 , то*/
{
//вывод j-той строки журнала
/*что то выведем....*/
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc <<endl;
//j=++j; //следующая строка журнала /*Бррр... Что то страшное*/
j++; /* так по-красивше будет*/
}
} //Повторять пока flag!=0 или i<1000

getch();
return 0;
}
/*Так теперь сами функции потока*/

//Функция потока:имитация ”чтения”корректировки
//и ”записи” разделяемой переменной F
//параметр-указатель на текущую строку журнала
DWORD WINAPI ThreadProc1(LPVOID Param)
{
/*Дали указатель на структуру....*/
_log* p = (_log*)Param;	
int Fbuf; /* Объявили переменную*/
//чтение разделяемой переменной в буферную переменную
WaitForSingleObject(Semaphore,-1); //Подождем пока не освободится семафор

Fbuf=F; /* прочитали глобальную переменную (до сих пор еще если честно не врубаюсь)*/
waiting(wtime); //задержка /*Подержим это дело... Опять же зачему эта функция поражает */

//корректировка буферной переменной
if (((*p).key >= 49)&&((*p).key <= 57)) /*Опять проверим клавиши*/
Fbuf=Fbuf+ p->key-48; /*Вычислим для некого дочернего результата*/

waiting(wtime);//задержка /*Опять подержим... А зачем???*/
//запись из буферной переменной в разделяемую переменную
F=Fbuf; /*Запишим это дело в глобальную переменную */
//запись результата в текущую строку журнала
(*p).F=F; /* пишим, можно было бы обойтись и без промежуточных переменных*/
(*p).t2=clock(); //время окончания работы потока /*Запишим время*/
ReleaseSemaphore(Semaphore,1,NULL); //Освободим семафор
return 0;
}

/* Как я понимаю аналогично прошлому*/
DWORD WINAPI ThreadProc2(LPVOID Param)
{
_log* p = (_log*)Param;
int Fbuf;
WaitForSingleObject(Semaphore,-1);
//чтение разделяемой переменной в буферную
Fbuf=F;
waiting(wtime); //задержка
//корректировка буферной переменной
if (((*p).key >= 120)&&((*p).key <= 128))
Fbuf=Fbuf-p->key+119;
waiting(wtime);//задержка
//запись результата из буферной переменной в разделяемую
F=Fbuf;
//запись результата в текущую строку журнала
(*p).F=F;
(*p).t2=clock(); //время окончания работы потока
ReleaseSemaphore(Semaphore,1,NULL);
return 0;
}

//функция задержки
//параметр – время задержки в мс
void waiting(clock_t dt) 
{
clock_t tn;
tn=clock();
while (clock()-tn < dt)
{

}
//return 0; /* Не подойдет */
return; /* В самый раз или вообще без него */
}
 
L

lazybiz

Внес некоторые коррективы. Принцип работы программы не изменился, но хотя бы читабельность улучшилась в несколько раз:
C++:
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <time.h>

using namespace std;

#define			DELAY()		Sleep( 100 );

HANDLE			hThread;
DWORD			IDThread;
int				F			= 0;
HANDLE			hSem;

struct _log {
int		nom;	// порядковый номер операции
int		key;	// код нажатой клавиши
DWORD	ID;		// идентификатор созданного потока
clock_t	t1;		// время начала операции
clock_t	t2;		// время завершения операции
int		F;		// результат операций в дочернем потоке
int		Fc;		// результат операций в главном потоке
} mylog[1000];		// неболее 1000 операций

DWORD WINAPI ThreadProc1( LPVOID );
DWORD WINAPI ThreadProc2( LPVOID ); 

int main()
{
int i = 0;
int j = 1;
int key = 1;
int flag = 1;
int Fcontr;
Fcontr = F;
hSem = CreateSemaphore( NULL, 1, 1, NULL );
while ( flag || i <= 1000 ) {
if ( kbhit() ) {
key = getche();
if ( (key >= 49) && (key <= 57) ) {
Fcontr += key - 48;
} else if ( (key >= 120) && (key <= 128) ) {
Fcontr -= key + 119;
}
if ( key == 27 ) {
flag = 0;
break;
}
i++;
mylog[i].nom	= i;
mylog[i].key	= key;
mylog[i].t2		= 0;
mylog[i].F		= 0;
mylog[i].Fc		= Fcontr;
mylog[i].t1		= clock();
if ( (key >= 49) && (key <= 57) ) {
hThread = CreateThread( NULL, 0, &ThreadProc1, &mylog[i], CREATE_SUSPENDED, &IDThread );
}
if ( (key >= 120) && (key <= 128) ) {
hThread = CreateThread( NULL, 0, &ThreadProc2, &mylog[i], CREATE_SUSPENDED, &IDThread );
}
if ( !hThread ) { 
cout << "Thread error" << key << endl;
return 0;
}
mylog[i].ID = IDThread;
ResumeThread( hThread );
}
if ( mylog[j].t2 != 0 ) {
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc <<endl;
}
}
getch();
return 0;
}

DWORD WINAPI ThreadProc1( LPVOID Param )
{
int		Fbuf;
_log *	p = (_log *)Param;
WaitForSingleObject( hSem, INFINITE );
Fbuf = F;
DELAY();
if ( (p->key >= 49) && (p->key <= 57) ) {
Fbuf += p->key - 48;
}
DELAY();
F = Fbuf;
p->F = F;
p->t2 = clock();
ReleaseSemaphore( hSem, 1, NULL );
return 0;
}

DWORD WINAPI ThreadProc2( LPVOID Param )
{
int		Fbuf;
_log *	p = (_log *)Param;
WaitForSingleObject( hSem, INFINITE );
Fbuf = F;
DELAY();
if ( (p->key >= 120) && (p->key <= 128) ) {
Fbuf -= p->key + 119;
}
DELAY();
F = Fbuf;
p->F = F;
p->t2 = clock();
ReleaseSemaphore( hSem, 1, NULL );
return 0;
}
Что она делает я так и не понял (да и особо не вникал), но что-то она делает это точно, по крайней мере компилируется.
 
D

DarkKnight

Не кстати логика у программы есть, очень даже не плохой пример для понимания синхронизации....
А функцию автора - "реализации задержки" - зря заменил... Реально классная штука ;-)
 
D

DarkKnight

Вот так вроде все возможные баги удалил:

C++:
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <time.h>
using namespace std; /*ДОБАВИЛ ДЛЯ std */

HANDLE hThread; //дискриптор создаваемого потока 
DWORD IDThread; //идентификатор потока
int F=0; //разделяемая глобальная переменная
clock_t wtime=100; //время задержки(мс)
HANDLE Semaphore; //Наш семафор

void waiting(clock_t dt); //функция задержки /*ВОТ ЭТО МЕСТНО - ВООБЩЕ ПОНРАВИЛОСЬ [+] */

struct _log /* ПЕРЕИМЕНОВАЛ структуру, а то с функцией конфликтует */
{
int nom; //порядковый номер операции
int key; //код нажатой клавиши
DWORD ID; //идентификатор созданного потока
clock_t t1; //время начала операции
clock_t t2; // время завершения операции
int F; //результат операций в дочернем потоке
int Fc; //результат операций в главном потоке
} mylog[1000]; //неболее 1000 операций

//DWORD ThreadProc1(_log*); //функция потока 1 (параметр - pointer на структуру log)
DWORD WINAPI ThreadProc1(LPVOID);/*В WIN-API Функция потока имеет имеено такой протатип */
DWORD WINAPI ThreadProc2(LPVOID); 
//DWORD ThreadProc2(_log*); //функция потока 2 (параметр - pointer на структуру log)

//=================================== ==============
int main() //главный поток
{
int i=0; //счётчик операций
int j=1; //счётчик вывода строк журнала
int key=1; //код нажатой клавиши
int flag=1; //признак завершения программы
int Fcontr; //переменная-дублёр
//mylog[1].t2=0; //признак того,что поток не завершён
Fcontr=F;
//Создадим 
Semaphore = CreateSemaphore(NULL,1,1,NULL);

//Повторять пока flag!=0 или i<1000
while (flag || i <=1000) /* Ну здесь вроде пока программа не завершится и i==1000*/
{
/*ВВЕДЕМ ЕЩЕ ОДИН ФЛАЖОК ДЛЯ ВЕРНОЙ РАБОТЫ ТВОЕЙ ПРОГРАММЫ*/
bool isTrue = false;
//Приём кода нажатой клавиши
if (kbhit() != 27 && key!=27) /*Предположим что приняли */
{
/*ТУТ У ТЕБЯ НЕ САМАЯ ЛУЧШАЯ РЕАЛИЗАЦИЯ с kbhit() была
нужно примерно на такую исправить*/
key = (unsigned char)getch();
//key= getchar(); 
//if (key==0) key=getch();
//Формирование переменной дублёра
if ((key>=49) && (key<=57))
{ /* Оно число*/
Fcontr=Fcontr+key-48;/* Увеличим некую переменную-дублер (пока еще не знаю что это правда) на цифру нажатой клавиши*/
isTrue = true;
}
//else if (key>=120) && (key<=128)) /* Как я понимаю если нажато что попало*/
else if ((key>=104) && (key<=113)) /* СДЕЛАЕМ ТАК alt+F1..alt+F9*/
{
Fcontr=Fcontr-key+103; /* То уменьшим странную переменную на что то */
isTrue = true;
}
//if (key==27) /* Если ESC - то досвидание*/
//{
//flag=0;
//break;
//}
//Формируем строку журнала 
if (isTrue) /* А ВОТ ТУТ МЫ ЭТОТ ФЛАЖОК ИСПОЛЬЗУЕМ */
{
i++; /*Увеличим счетчик, сразу возникает вопрос, а что с первым элементом то mylog[0]? */
mylog[i].nom=i; /* Запишим номер будем считать его ID-уникальным индексом */
mylog[i].key=key; /* Клавишу */
mylog[i].t2=0; /* Обнулим время завершения*/
mylog[i].F=0;/*Рузультат в доч. потоке (это я пока что тоже не понимаю) */
mylog[i].Fc=Fcontr; /* Запишим результат в главном потоке, равеной чудо переменной-дублеру (я аж заинтригован) */
mylog[i].t1=clock(); /* Начало выполнение запишим */
}
//Создание потока 1 без немедленного запуска
if ((key>=49) && (key<=57)) /* Если клавиша все же циферная */
{
hThread= CreateThread(NULL,0,&ThreadProc1,&mylog[i],CREATE_SUSPENDED,&IDThread);/* Согласен*/
}
//if ((key>=120) && (key<=128)) /* Если что попало, то*/
if ((key>=104) && (key<=113)) /* СДЕЛАЕМ ТАК alt+F1..alt+F9*/
{
hThread= CreateThread(NULL,0,&ThreadProc2,&mylog[i],CREATE_SUSPENDED,&IDThread); /* То сделаем тоже самое, но ч другим потоком.. не помню точно,
что именно содержится в кодах от 120 до 128
и что точно отбрасывается от 58..119, но думаю какой то
определенный смысл в этом есть*/
}
//Проверяем создался ли поток
if (hThread == NULL) /* Согласен*/
{ 
cout << "Thread error" << key << endl;
getch();
return 0;
}
else
{
mylog[i].ID=IDThread; //Запишим в структуру IDпотока
ResumeThread(hThread); /*Запустим поток*/
}
}

/*А вот в этом месте уже не допонимаю*/
//Завершение работы потока проверяется по сформированному в функции потока значению времени t2

if (mylog[j].t2 != 0) /* Хм... Если у j-потока конечное время не равно 0 , то*/
{
//вывод j-той строки журнала
/*что то выведем....*/
cout << j << " " << mylog[j].key << " " << mylog[j].ID << " " << mylog[j].t1 << " " << mylog[j].t2 << " " << mylog[j].F << " " << mylog[j].Fc <<endl;
//j=++j; //следующая строка журнала /*Бррр... Что то страшное*/
j++; /* так по-красивше будет*/
}
} //Повторять пока flag!=0 или i<1000

getch();
return 0;
}
/*Так теперь сами функции потока*/

//Функция потока:имитация ”чтения”корректировки
//и ”записи” разделяемой переменной F
//параметр-указатель на текущую строку журнала
DWORD WINAPI ThreadProc1(LPVOID Param)
{
/*Дали указатель на структуру....*/
_log* p = (_log*)Param;	
int Fbuf; /* Объявили переменную*/
//чтение разделяемой переменной в буферную переменную
WaitForSingleObject(Semaphore,-1); //Подождем пока не освободится семафор

Fbuf=F; /* прочитали глобальную переменную (до сих пор еще если честно не врубаюсь)*/
waiting(wtime); //задержка /*Подержим это дело... Опять же зачему эта функция поражает */

//корректировка буферной переменной
if (((*p).key >= 49)&&((*p).key <= 57)) /*Опять проверим клавиши*/
Fbuf=Fbuf+ p->key-48; /*Вычислим для некого дочернего результата*/

waiting(wtime);//задержка /*Опять подержим... А зачем???*/
//запись из буферной переменной в разделяемую переменную
F=Fbuf; /*Запишим это дело в глобальную переменную */
//запись результата в текущую строку журнала
(*p).F=F; /* пишим, можно было бы обойтись и без промежуточных переменных*/
(*p).t2=clock(); //время окончания работы потока /*Запишим время*/
ReleaseSemaphore(Semaphore,1,NULL); //Освободим семафор
return 0;
}

/* Как я понимаю аналогично прошлому*/
DWORD WINAPI ThreadProc2(LPVOID Param)
{
_log* p = (_log*)Param;
int Fbuf;
WaitForSingleObject(Semaphore,-1);
//чтение разделяемой переменной в буферную
Fbuf=F;
waiting(wtime); //задержка
//корректировка буферной переменной
if (((*p).key >= 120)&&((*p).key <= 128))
Fbuf=Fbuf-p->key+119;
waiting(wtime);//задержка
//запись результата из буферной переменной в разделяемую
F=Fbuf;
//запись результата в текущую строку журнала
(*p).F=F;
(*p).t2=clock(); //время окончания работы потока
ReleaseSemaphore(Semaphore,1,NULL);
return 0;
}

//функция задержки
//параметр – время задержки в мс
void waiting(clock_t dt) 
{
clock_t tn;
tn=clock();
while (clock()-tn < dt)
{

}
//return 0; /* Не подойдет */
return; /* В самый раз или вообще без него */
}
 
L

lazybiz

А функцию автора - "реализации задержки" - зря заменил... Реально классная штука ;-)
Хе) Авторский вариант грузит поток или целиком процесс на 100% !!! В то время как примитивный Sleep() данным косяком не страдает. А теперь вопрос: что в ней классного?
 
D

DarkKnight

Сама реализация.... Есть интересные реализации - есть нет, автора реализация очень интересна с моего взгляда, пусть она не продуктивна и процессорно емка, зато сразу бросается в глаза...
 
L

lazybiz

Я не вижу в реализации этой функции никаких плюсов. Зачем усложнять себе задачу. Вот оно - Sleep() - уже есть!
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!