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

Тема в разделе "C и С++ FAQ", создана пользователем -, 9 окт 2010.

  1. Гость

    Помогите синхронизировать потоки с помощью семафора.С++ с использованием стандартных функций 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;
    }
    Заранее благодарю за помощь =)
     
  2. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

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

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Щас глянем...
    Сразу встречный вопрос в чем именно писал? И каким компилятором компилировал?
    А то сразу смотрю на имя структуры (log) - точно знаю MS VC - такое не прохавает
     
  4. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Код (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; /* В самый раз или вообще без него */
    }
    Это все что касается синтаксиса...
     
  5. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Примерно что то вроде такого:
    Ну синхронизаця точно работать будет....
    а вот 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; /* В самый раз или вообще без него */
    }
     
  6. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Внес некоторые коррективы. Принцип работы программы не изменился, но хотя бы читабельность улучшилась в несколько раз:
    Код (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;
    }
    Что она делает я так и не понял (да и особо не вникал), но что-то она делает это точно, по крайней мере компилируется.
     
  7. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Не кстати логика у программы есть, очень даже не плохой пример для понимания синхронизации....
    А функцию автора - "реализации задержки" - зря заменил... Реально классная штука ;-)
     
  8. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Вот так вроде все возможные баги удалил:

    Код (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; /* В самый раз или вообще без него */
    }
     
  9. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Хе) Авторский вариант грузит поток или целиком процесс на 100% !!! В то время как примитивный Sleep() данным косяком не страдает. А теперь вопрос: что в ней классного?
     
  10. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Сама реализация.... Есть интересные реализации - есть нет, автора реализация очень интересна с моего взгляда, пусть она не продуктивна и процессорно емка, зато сразу бросается в глаза...
     
  11. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Я не вижу в реализации этой функции никаких плюсов. Зачем усложнять себе задачу. Вот оно - Sleep() - уже есть!
     
Загрузка...

Поделиться этой страницей