Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> SetWaitableTimer(), как задать период срабатывания таймера 
V
    Опции темы
wallstreet
Дата 11.3.2012, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Всем доброго дня.
Задача стоит раз в секунду одним потоком выделить область для данных, вторым заполнить, третим отобразить.
Период в секунду нужно отобразить скорее всего ожидаемым таймером.
Делаю вот так:
Код

static int **buf;
CRITICAL_SECTION cs;
int j;
TCHAR str[10];
HANDLE hTimer;
unsigned _stdcall Thread1(void *param)
{
    EnterCriticalSection(&cs);
    WaitForSingleObject(hTimer, INFINITE);
    buf = new int*[10]; // 10 строк в массиве
        for(int i=0; i<10; i++)
            buf[i] = new int[10]; // 10 столбцов в массиве
        LeaveCriticalSection(&cs);
    return 0;
}
unsigned _stdcall Thread2(void *param)
{
    // ЗАПОЛНЕНИЕ МАССИВА
    EnterCriticalSection(&cs);
    WaitForSingleObject(hTimer, INFINITE);
    for(int count_row=0; count_row<10; count_row++)
        for(int count_column=0; count_column<10; count_column++)
            buf[count_row][count_column] = j++;
    LeaveCriticalSection(&cs);
    return 0;
}
unsigned _stdcall Thread3(void *param)
{
    WaitForSingleObject(hTimer, INFINITE);
    // Перерисовка окна
    InvalidateRect((HWND)param, NULL, TRUE);
    return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    int x = 0;
    int y = 0;
    LARGE_INTEGER lTime;  // устанавливаем период через который таймер освободит объект для потоков
    static HANDLE hThread1, hThread2, hThread3;

    switch (message)
    {
    case WM_CREATE:
        InitializeCriticalSection(&cs);
        lTime.QuadPart = -10000000;
        hTimer = CreateWaitableTimer(NULL, TRUE, NULL); //создаем ожидаемый таймер
        SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE); // установим основные настройки таймера

        hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, hWnd, 0, NULL);
        hThread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, hWnd, 0, NULL);
        hThread3 = (HANDLE)_beginthreadex(NULL, 0, Thread3, hWnd, 0, NULL);
    break;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            for(int count=0; count<10; count++)
                delete []buf[count];
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // Вывод содержимого в окно
        EnterCriticalSection(&cs);
        for(int count_row=0; count_row<10; count_row++)
                for(int count_column=0; count_column<10; count_column++)
                {
                    y=count_row*20;
                    x=count_column*20;
                    _itot(buf[count_row][count_column], str, 10);
                    TextOut(hdc, x, y, str, _tcslen(str));
                }
        LeaveCriticalSection(&cs);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        CloseHandle(hThread1);
        CloseHandle(hThread2);
        CloseHandle(hThread3);
        DeleteCriticalSection(&cs);
        CancelWaitableTimer(hTimer);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}



В результате таблица один раз отрисовывается и все, хотя третий параметр функции SetWaitableTimer(...,...,1000,...,...,...) равен насколько я понимаю одной секунде. т.е. после первой отрисовки J = 99 и следующая должна начаться с этого значения.
Что делаю не так?


блин код как-то не так отображаться стал, поэтому нужную строку подсветил



Это сообщение отредактировал(а) GremlinProg - 15.3.2012, 07:13
PM MAIL   Вверх
Dem_max
Дата 11.3.2012, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 16
Всего: 39



Код

void __fastcall TForm1::Timer() 
{ 
int iDay; 
TDateTime DTime; 
FILETIME Local, UTC; 
SYSTEMTIME st, stmp; 
LARGE_INTEGER li; 
char *S = "USSSSSSS"; 

GetLocalTime(&stmp); 
HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL); 
DateTimeToSystemTime(DateTimePicker1->Time, st); 
if(stmp.wHour < st.wHour) 
      { 
        stmp.wHour = st.wHour; 
        stmp.wMinute = st.wMinute; 
      } 
else if((stmp.wHour == st.wHour)&&(stmp.wMinute < st.wMinute)) 
        stmp.wMinute = st.wMinute; 
else return; 

SystemTimeToFileTime(&stmp, &Local); 
LocalFileTimeToFileTime(&Local, &UTC); 
li.LowPart = UTC.dwLowDateTime; 
li.HighPart = UTC.dwHighDateTime; 
SetWaitableTimer(hTimer,&li,0,Syn,S,FALSE); 
SleepEx(INFINITE,true); 

}




--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
wallstreet
Дата 11.3.2012, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



а вот так можно устанавливать время постоянного срабатывания с интервалом 1 сек:
Код

 lTime.QuadPart = -10000000;
 hTimer = CreateWaitableTimer(NULL, TRUE, NULL); 
 SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE); 


или обязательно создавать переменную системного времени и приводить их к FILETIME
а потом уже использовать???? Думаю что нет.. Разве что если нам надо что бы таймер 
сработал в определенное время, тогда да. А в данном случае мой таймер освобождается
для потоков через 10 сек после создания и так через 1 сек в дальнейшем должно быть, но не получается

Это сообщение отредактировал(а) wallstreet - 11.3.2012, 21:08
PM MAIL   Вверх
feodorv
Дата 11.3.2012, 23:08 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(wallstreet @  11.3.2012,  17:19 Найти цитируемый пост)
раз в секунду

В коде этого нет. Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся.

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

Поскольку для отрисовки (в любой момент времени!) данных эти самые данные необходимо иметь, то, действительно, эти данные необходимо защитить от одновременного доступа. Критическая секция здесь подойдёт лучше всего, но не просто потому, что проще всего, а потому, что не имеет принадлежности к потоку, вызвавшему EnterCriticalSection (то есть освободить секцию мы можем в любом другом потоке!). Именно этим свойством я и предлагаю воспользоваться.

Но ещё раз скажу, что задача осложняется тем, что:
  • запрос на отрисовку может прийти в любой момент (у Вас это учтено критической секцией)
  • потоки должны пробуждаться в нужной последовательности (освобождение/выделение памяти -> инициализация -> отрисовка), но никак не в произвольном (у Вас это не учтено, так как порядок доступа к критической секции может отличаться от запланированного).
Поэтому предлагаю будить первый поток через таймер, второй поток - через событие2, третий - через событие3. Критическую секцию захватываем в первом потоке, а высвобождаем только в третьем! Ну, и отрисовку тоже защищаем критической секцией.

Таким образом получается:

Первый поток
Цикл по:
  • ожидание таймера или события1
  • проверяем, не нужно ли потоку заканчивать работу
  • захватываем критическую секцию
  • высвобождаем память, если она уже была заказана
  • заказываем память
  • устанавливаем событие2
  • идём на новый виток цикла
Второй поток
Цикл по:
  • ожидание события2
  • проверяем, не нужно ли потоку заканчивать работу
  • сбрасываем событие2
  • инициализируем выделенную память
  • устанавливаем событие3
  • идём на новый виток цикла
Третий поток
Цикл по:
  • ожидание события3
  • проверяем, не нужно ли потоку заканчивать работу
  • сбрасываем событие3
  • высвобождаем критическую секцию
  • вызываем InvalidateRect
  • идём на новый виток цикла
Таким образом мы гарантируем правильную очерёдность выполнения потоков и одновременно не допущения к данным памяти процедуры отрисовки.

Однако даже в таком варианте схема имеет изъян. Он связан с тем, что за время между срабатываниями таймера второй поток может не успеть проинициализировать данные, и при следующем срабатывании таймера первый поток начнёт перезаказывать память, а второй будет всё ещё инициализировать выделенную в прошлый раз память. Такая ситуация лечится тем, что придётся ввести вторую критическую секцию, которой обычным образом дополнительно защищаются данные в первом и втором потоках, ну с этим Вы справитесь самостоятельно...

ЗЫ События 1, 2 и 3 также используются для корректного завершения приложения.

Это сообщение отредактировал(а) feodorv - 11.3.2012, 23:17


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 12.3.2012, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Огромное спасибо всем за участие.
Цитата

Цитата(wallstreet @  11.3.2012,  17:19 )


раз в секунду


В коде этого нет. Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся.
 


Надо сделать. В этом собственно и загвоздка. Из определения:
ОЖИДАЕМЫЕ ТАЙМЕРЫ - объекты ядра, которые самосоятельно переходят в свободное состояние в определенное время или через 
регулярные промежутки времени.

Вот мне этот промежуток и не удается задать((

Ну а теперь по порядку.
Цитата

■ожидание таймера или события1

А кто событие для первого потока будет освобождать? Предполагаю что поток 3й или раздел отрисовки окна WM_PAINT?


Цитата

■проверяем, не нужно ли потоку заканчивать работу

Насколько я понял, чо проверять должны на выполнение условия, т.е. применительно к потоку1, память под массив выделена, значит освобождаем событие1 переходим во второй поток который завершает первый или как?

Вот что получилось:
Код

static int **buf;
CRITICAL_SECTION cs1, cs2;
int j;
TCHAR str[10];
HANDLE hTimer;
static HANDLE hEvent1, hEvent2;

unsigned _stdcall Thread1(void *param)
{
    EnterCriticalSection(&cs1);            // Захватываем критическую секцию 1
    WaitForSingleObject(hTimer, INFINITE); // Ждем свободного состояния таймера
    EnterCriticalSection(&cs2);            // Захватываем критическую секцию 2
    if(!buf)                               // Проверяем массив на заполненние
    {
    // СОЗДАНИЕ НОВОГО МАССИВА
    buf = new int*[10];                    // 10 строк в массиве
        for(int i=0; i<10; i++)
            buf[i] = new int[10];          // 10 столбцов в массиве
    }
    else                                   // если память выделена на массив, заполняем нулями
    {
        for(int count_row=0; count_row<10; count_row++)
            for(int count_column=0; count_column<10; count_column++)
                buf[count_row][count_column] = 0;
    }
    SetEvent(hEvent1);                     // Освобождаем событие 1
    LeaveCriticalSection(&cs2);            // Освобождаем критическую секцию 2
    return 0;
}
unsigned _stdcall Thread2(void *param)
{
    WaitForSingleObject(hEvent1, INFINITE); // Ждем перехода события 1 в свободное состояние
    EnterCriticalSection(&cs2);             // Захватываем критическую секцию 2
    // ЗАПОЛНЕНИЕ МАССИВА
    for(int count_row=0; count_row<10; count_row++)
        for(int count_column=0; count_column<10; count_column++)
            buf[count_row][count_column] = j++;
    SetEvent(hEvent2);                      // Освобождаем событие 2
    LeaveCriticalSection(&cs2);             // Освобождаем критическую секцию 2
    return 0;
}
unsigned _stdcall Thread3(void *param)
{
    WaitForSingleObject(hEvent2, INFINITE); // Ждем перехода события 2 в свободное состояние
    EnterCriticalSection(&cs2);             // Захватываем критическую секцию 2
    // СООБЩЕНИЕ НА ПЕРЕРИСОВКУ ОКНА
    InvalidateRect((HWND)param, NULL, TRUE);
    EnterCriticalSection(&cs2);             // Освобождаем критическую секцию 2
    LeaveCriticalSection(&cs1);             // Освобождаем критическую секцию 1
    return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    int x = 0;
    int y = 0;
    LARGE_INTEGER lTime;                   // устанавливаем период через который таймер освободит объект для потоков
    static HANDLE hThread1, hThread2, hThread3;

    switch (message)
    {
    case WM_CREATE:
        InitializeCriticalSection(&cs1);  // Инициализируем критическую секцию 1
        InitializeCriticalSection(&cs2);  // Инициализируем критическую секцию 2
        hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 1
        hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 2
        lTime.QuadPart = -10000000;                      // Задаем время первого срабатывания таймера после создания
        hTimer = CreateWaitableTimer(NULL, FALSE, NULL); //создаем ожидаемый таймер
        SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE); // установим основные настройки в таймер
        hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, hWnd, 0, NULL);
        hThread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, hWnd, 0, NULL);
        hThread3 = (HANDLE)_beginthreadex(NULL, 0, Thread3, hWnd, 0, NULL);
    break;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            for(int count=0; count<10; count++)
                delete []buf[count];
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // Вывод содержимого в окно
        EnterCriticalSection(&cs1);           // Захватываем критическую секцию 1
        for(int count_row=0; count_row<10; count_row++)
                for(int count_column=0; count_column<10; count_column++)
                {
                    y=count_row*20;
                    x=count_column*20;
                    _itot(buf[count_row][count_column], str, 10);
                    TextOut(hdc, x, y, str, _tcslen(str));
                }
        LeaveCriticalSection(&cs1);           // Освобождаем критическую секцию 1
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        CloseHandle(hThread1);
        CloseHandle(hThread2);
        CloseHandle(hThread3);
        CloseHandle(hEvent1);
        CloseHandle(hEvent2);
        DeleteCriticalSection(&cs1);
        DeleteCriticalSection(&cs2);
        CancelWaitableTimer(hTimer);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}



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

Это сообщение отредактировал(а) wallstreet - 12.3.2012, 18:32
PM MAIL   Вверх
feodorv
Дата 12.3.2012, 23:36 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Было бы проще, если бы в доступности находился весь проект)))
Несколько замечаний:

1/ 
Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
       hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 1
        hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 2

Если мы создаём события со сбросом вручную, то 
Код

       hEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL); // Создаем событие 1
        hEvent2 = CreateEvent(NULL, TRUE, FALSE, NULL); // Создаем событие 2

Правда, тогда нужны соответствующие ResetEvent в нужных местах...


2/
Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
    EnterCriticalSection(&cs1);            // Захватываем критическую секцию 1
    WaitForSingleObject(hTimer, INFINITE); // Ждем свободного состояния таймера
    EnterCriticalSection(&cs2);            // Захватываем критическую секцию 2

Всё-таки мы сначала ждём таймера, а уже потом захватываем cs1... Этим мы даём возможность окну отрисовать клиенскую область при разных событиях (схлопывание-раскрытие окна, перекрытие окна, завершение работы...):
Код

    WaitForSingleObject(hTimer, INFINITE); // Ждем свободного состояния таймера
    EnterCriticalSection(&cs1);            // Захватываем критическую секцию 1
    EnterCriticalSection(&cs2);            // Захватываем критическую секцию 2

Ну и устанавливать события можно вне сферы деятельности критической секции...


3/ 
Цитата(feodorv @  12.3.2012,  00:08 Найти цитируемый пост)
проверяем, не нужно ли потоку заканчивать работу

Имелось ввиду, что если потоки будут бесперерывно работать, то их нужно корректно завершить при завершении всего приложения (при IDM_EXIT).  Обычно это делается так: заводится глобальная булева переменная (назовём её done), которая принимает значение TRUE только при необходимости завершить работу, а все созданные потоки пробуждаются тем или иным способом. Но поскольку Thread1 висит исключительно на таймере, то для завершения потока нужно дожидаться срабатываения таймера (для 1 секунды это терпимо, а если нужно было раз в минуту?) Для этого и вводилось соответствующее событие в Thread1, которое сбрасывалось бы только при IDM_EXIT.


4/ 
Цитата(feodorv @  12.3.2012,  00:08 Найти цитируемый пост)
Цикл по:

Вот это отсутствует smile Из-за этого
Цитата(feodorv @  12.3.2012,  00:08 Найти цитируемый пост)
Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся.

Иными словами, нужно так:
Код

BOOL done = FALSE;

unsigned _stdcall Thread1(void *param)
{
  HANDLE list[2];

  list[0] = hEvent0;
  list[1] = hTimer;
 
  while( !done )
  {
    WaitForMultipleObjects( 2, list, FALSE, INFINITE); // Ждем свободного состояния таймера
    if( done ) break;
    EnterCriticalSection(&cs1);            // Захватываем критическую секцию 1
    EnterCriticalSection(&cs2);            // Захватываем критическую секцию 2
    ...
    LeaveCriticalSection(&cs2);            // Освобождаем критическую секцию 2
    SetEvent(hEvent1);                     // Освобождаем событие 1
  }
  return 0;
}

Аналогично и в других потоках!!!


4/ Завершение приложения - отдельная песня. Ибо необходимо дождаться завершения всех трёх потоков через WaitForMultipleObjects, предварительно установив done в TRUE и пробудив потоки через SetEvent. Ждать можно максимум 10 секунд...
Код

done = TRUE;
SetEvent( hEvent0 );
SetEvent( hEvent1 );
SetEvent( hEvent2 );

HANDLE list[3];
list[0] = hThread1;
list[1] = hThread2;
list[2] = hThread3;
WaitForMultipleObjects( 3, list, TRUE, 10000); // Ждём завершения всех трёх потоков

И уже потом DestroyWindow()...


5/ при отрисовке нужно учитывать, что buf может быть NULL (например, если отрисовка произойдёт быстрее, чем первый поток успеет захватить критическую секцию), тогда просто можно ничего не рисовать. Гм, нужно также проследить, что Вы очищаете клиенскую область окна при перерисовке...


Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
А кто событие для первого потока будет освобождать? 

Мы будем ждать или-или (а не и-и), поэтому если сработает таймер, то и поток1 пробудится. Про событие и его роль уже написал  smile 


Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
Вот мне этот промежуток и не удается задать((

Во-первых, потоки отрабытывают всего один раз, сколько бы раз там таймер не срабатывал... Во-вторых, зачем эта задержка:
Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
lTime.QuadPart = -10000000;                      // Задаем время первого срабатывания таймера после создания

Почему не просто 0? А так, на вид, всё правильно)))
В сущности, можно было бы начать писать программу с одного потока, сидящего на таймере, а два других добавить позже, когда таймер заработает...


Цитата(wallstreet @  12.3.2012,  19:30 Найти цитируемый пост)
Вообщем, так, к слову, в задаче нужно было обойтись исключительно критическими секциями.

Ну, эээ, теоретически, можно всё переписать исключительно через критические секции, но это будет сильно напряжно)))


Так что потихоньку двигаемся к финишу)))

Это сообщение отредактировал(а) feodorv - 12.3.2012, 23:48


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 13.3.2012, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Ну вроде подогнал под ваши рекомендации.
По пунктам:

1\ 
А зачем нам создавать события с ручным сбросом. Мы дождались освобождения события и оно автоматом занимается потоком дождавшимся. Т.о. мы создаем событие занятым изначально, потом первый поток его освобождает для второго, а второй дождавшись занимает ну и тд. 

2\ 
реализовал по примеру  4\ 

3\ 
реализовал в IDM_EXIT после чего при попытке выхода путем Menu\Exit прога висит секунд 5, потом закрывает окно.  Однако для меня немного непонятным остается, что значит:
Цитата

Но поскольку Thread1 висит исключительно на таймере, то для завершения потока нужно дожидаться срабатываения таймера (для 1 секунды это терпимо, а если нужно было раз в минуту?)


4\ 
В целом не понимаю зачем завершать поток при выходе? Он ведь в рамках процесса окна создается, насколько я понимаю, соответственно и завершится по завершению процесса окна при выходе. Ну и путаница в голове по поводу освобождения событий возникает. Допустим осбытие0 освободилось, но при проверке done на TRUE нас сразу выкинет из потока но не завершит. Ведь насколько я понимаю завершение потока происходит с помощью функции _endthreadex(). Т.о. почему бы просто не взять и не завершить этой функцией все потоки по очереди в IDM_EXIT? Вобщем хотелось бы поподробнее о выходе.

5\
Вроде все ок.
Цитата

lTime.QuadPart = -10000000;

для того что бы визуально видеть что таймер срабатывает. А так можно и 0

Кстати что делать с отрисовкой раз в секунду моих данных?

Архив с проектом

Код

static int **buf;                             // Буфер для данных
CRITICAL_SECTION cs1, cs2;                    // Критические секции
int j; 
TCHAR str[10];                                // Строка для отрисовки
HANDLE hTimer;                                // Хендл таймера
static HANDLE hEvent0, hEvent1, hEvent2;      // Хендлы событий
BOOL done = FALSE;

unsigned _stdcall Thread1(void *param)
{
    HANDLE list[2];
    list[0] = hEvent0;
    list[1] = hTimer;

    while(!done)
    {
        WaitForMultipleObjects(2, list, FALSE, INFINITE); // Ждем свободного состояния таймера или освобождения события 0
        if(done)
            break;
        EnterCriticalSection(&cs1);            // Захватываем критическую секцию 1
        EnterCriticalSection(&cs2);            // Захватываем критическую секцию 2
        if(!buf)                               // Проверяем массив на заполненние
        {
        // СОЗДАНИЕ НОВОГО МАССИВА
        buf = new int*[10];                    // 10 строк в массиве
            for(int i=0; i<10; i++)
                buf[i] = new int[10];          // 10 столбцов в массиве
        }
        else                                   // если память выделена на массив, заполняем нулями
        {
            for(int count_row=0; count_row<10; count_row++)
                for(int count_column=0; count_column<10; count_column++)
                    buf[count_row][count_column] = 0;
        }
        SetEvent(hEvent1);                     // Освобождаем событие 1
        LeaveCriticalSection(&cs2);            // Освобождаем критическую секцию 2
    }
    return 0;
}
unsigned _stdcall Thread2(void *param)
{
    while(!done)
    {
        WaitForSingleObject(hEvent1, INFINITE); // Ждем перехода события 1 в свободное состояние
        if(done)
            break;
        EnterCriticalSection(&cs2);             // Захватываем критическую секцию 2
        // ЗАПОЛНЕНИЕ МАССИВА
        for(int count_row=0; count_row<10; count_row++)
            for(int count_column=0; count_column<10; count_column++)
                buf[count_row][count_column] = j++;
        SetEvent(hEvent2);                      // Освобождаем событие 2
        LeaveCriticalSection(&cs2);             // Освобождаем критическую секцию 2
    }
    return 0;
}
unsigned _stdcall Thread3(void *param)
{
    while(!done)
    {
        WaitForSingleObject(hEvent2, INFINITE); // Ждем перехода события 2 в свободное состояние
        if(done)
            break;
        EnterCriticalSection(&cs2);             // Захватываем критическую секцию 2
        // СООБЩЕНИЕ НА ПЕРЕРИСОВКУ ОКНА
        InvalidateRect((HWND)param, NULL, TRUE);
        EnterCriticalSection(&cs2);             // Освобождаем критическую секцию 2
        LeaveCriticalSection(&cs1);             // Освобождаем критическую секцию 1
    }
    return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    int x = 0;
    int y = 0;
    LARGE_INTEGER lTime;                   // устанавливаем период через который таймер освободит объект для потоков
    static HANDLE hThread1, hThread2, hThread3;

    switch (message)
    {
    case WM_CREATE:
        InitializeCriticalSection(&cs1);  // Инициализируем критическую секцию 1
        InitializeCriticalSection(&cs2);  // Инициализируем критическую секцию 2

        hEvent0 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 0
        hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 1
        hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL); // Создаем событие 2

        lTime.QuadPart = -10000000;                      // Задаем время первого срабатывания таймера после создания
        hTimer = CreateWaitableTimer(NULL, FALSE, NULL); //создаем ожидаемый таймер
        SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE); // установим основные настройки в таймер

        hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, hWnd, 0, NULL); // Создаем поток 1
        hThread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, hWnd, 0, NULL); // Создаем поток 2
        hThread3 = (HANDLE)_beginthreadex(NULL, 0, Thread3, hWnd, 0, NULL); // Создаем поток 3
    break;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            done = TRUE;
            SetEvent(hEvent0);
            SetEvent(hEvent1);
            SetEvent(hEvent2);
            HANDLE list[3];
            list[0] = hThread1;
            list[1] = hThread2;
            list[2] = hThread3;
            WaitForMultipleObjects(3, list, TRUE, 10000); // Ждем завершения всех потоков
            CloseHandle(hThread1);                        // Закрываем хендлы потоков и событий
            CloseHandle(hThread2);
            CloseHandle(hThread3);
            CloseHandle(hEvent0);
            CloseHandle(hEvent1);
            CloseHandle(hEvent2);
            DeleteCriticalSection(&cs1);                  // Удаляем критические секции
            DeleteCriticalSection(&cs2);
            CancelWaitableTimer(hTimer);                  // Останавливаем таймер
            for(int count=0; count<10; count++)           // Чистим память выделенную под буфер
                delete []buf[count];
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // ОТРИСОВКА ДАННЫХ В ОКНЕ
        if(buf)                                   // Отрисовываем данные, только если они есть
        {
            EnterCriticalSection(&cs1);           // Захватываем критическую секцию 1
            for(int count_row=0; count_row<10; count_row++)
                    for(int count_column=0; count_column<10; count_column++)
                    {
                        y=count_row*20;
                        x=count_column*20;
                        _itot(buf[count_row][count_column], str, 10);
                        TextOut(hdc, x, y, str, _tcslen(str));
                    }
            LeaveCriticalSection(&cs1);           // Освобождаем критическую секцию 1
        }
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}


Большое спасибо за помощь.

Это сообщение отредактировал(а) wallstreet - 13.3.2012, 14:00
PM MAIL   Вверх
feodorv
Дата 13.3.2012, 23:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
Архив с проектом

Спасибо!
В конце концов удалось скомпилиться и запуститься))))


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
Кстати что делать с отрисовкой раз в секунду моих данных?

Просто у Вас ошибка в Thread3:
Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
        EnterCriticalSection(&cs2);             // Захватываем критическую секцию 2
        // СООБЩЕНИЕ НА ПЕРЕРИСОВКУ ОКНА
        InvalidateRect((HWND)param, NULL, TRUE);
        EnterCriticalSection(&cs2);             // Освобождаем критическую секцию 2

Мало того, что там совсем не нужно защищать код критической секцией, так ещё и EnterCriticalSection(&cs2); два разА прописано (типичный копи-паст баг))))
СтОит только оставить:
Код

        InvalidateRect((HWND)param, NULL, TRUE);

И обновление идёт)))) Правда, как я уже говорил:
Цитата(feodorv @  13.3.2012,  00:36 Найти цитируемый пост)
Гм, нужно также проследить, что Вы очищаете клиенскую область окна при перерисовке...

Ну, это Вы уж как-нибудь сами)))


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
А зачем нам создавать события с ручным сбросом.

Ну, в данном случае не нужно))) Так как у нас один поток = одно событие. При другом раскладе стОит сделать выбор...


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
после чего при попытке выхода путем Menu\Exit прога висит секунд 5, потом закрывает окно. 

А у меня не висит ни секундочки (release) smile Это, правда, после вышеозначенного исправления)))


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
Однако для меня немного непонятным остается, что значит:
Цитата
Но поскольку Thread1 висит исключительно на таймере, то для завершения потока нужно дожидаться срабатываения таймера (для 1 секунды это терпимо, а если нужно было раз в минуту?)

В первоначальном варианте события hEvent0 не было, а без него поток пробуждался исключительно по таймеру. И сделав WaitForObject(s) (hThread1) мы бы зависли до тех пор, пока не сработал бы таймер, пробудив поток. Используя hEvent0, мы не зависим от таймера (при пробуждении первого потока).


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
Ведь насколько я понимаю завершение потока происходит с помощью функции _endthreadex().

Где?)))
_endthreadex() вызывается функцией _beginthreadex() по окончании выполнения функции потока. А Вы функцию потока завершать никак не хотели))) И мы бы остались с тремя потоками при завершении программы. Их бы всё равно прибила операционная система (при возврате из WinMain) посредством TerminateThread, но этого допускать не следует, так как при внезапной кончине одного потока другой поток своими действиями может вызвать нарушение доступа.


Цитата(wallstreet @  13.3.2012,  14:55 Найти цитируемый пост)
Т.о. почему бы просто не взять и не завершить этой функцией все потоки по очереди в IDM_EXIT?

Гм. Вот как раз по тем самым причинам.  Представьте себе, Вы говорите программе "Exit", а она: "Access violation..." Не комильфо)))
Самый лучший вариант - дать потоку завершиться самому.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 14.3.2012, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Оооо, да.
Ошибка зачетная была...
Ну теперь все работает как часы. 
Примного благодарствую)
PM MAIL   Вверх
GremlinProg
Дата 14.3.2012, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  12.3.2012,  01:08 Найти цитируемый пост)
Критическая секция здесь подойдёт лучше всего, но не просто потому, что проще всего, а потому, что не имеет принадлежности к потоку, вызвавшему EnterCriticalSection (то есть освободить секцию мы можем в любом другом потоке!). Именно этим свойством я и предлагаю воспользоваться.

вот EnterCriticalSection как раз имеет такую принадлежность,
а то, что LeaveCriticalSection может освободить чужую секцию можно расценивать как избыточную функциональность, которая может приводить к различным ошибкам
Цитата(LeaveCriticalSection Function @  MSDN)

If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

я бы не советовал пользоваться таким свойством
Цитата(wallstreet @  12.3.2012,  20:30 Найти цитируемый пост)
в задаче нужно было обойтись исключительно критическими секциями

судя по условию, задача учит просто синхронизировать доступ к массиву, управляемому разными потоками,
это не значит, что на секциях должно быть все
Цитата(feodorv @  12.3.2012,  01:08 Найти цитируемый пост)
По смыслу задачи, сначала отрабатывает первый поток с выделением памяти, уже потом должен отрабатывать второй поток с инициализацией, а, гм, третий (но есть ещё один наш, изначальный поток) должен заняться отрисовкой (в реальности он лишь посылает сообщение в оконную процедуру)

не надо пытаться думать о том, что какой-то поток дожен отработать раньше другого, это движение мыслей неправильное,
и приведет лишь к потерям времени, денег, нервов

если есть топологические отношения между потоками, значит они должны разрешаться синхронизаторами, по одному на каждое такое отношение, иначе стоит подумать о том, чтобы преобразовать такие потоки в один автомат
Цитата(wallstreet @  11.3.2012,  18:19 Найти цитируемый пост)
третим отобразить

отобразить, нарисовать - граница нечеткая,
но если нарисовать, то здесь основной поток вообще должен просто отобразить готовую картинку, которую третий поток как раз и формирует


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 14.3.2012, 19:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  14.3.2012,  13:29 Найти цитируемый пост)
вот EnterCriticalSection как раз имеет такую принадлежность

Ок. Скажу иначе: потоку, захватившему критическую секцию, не передаются права владения ею (в отличии от мютекса). 


Цитата(GremlinProg @  14.3.2012,  13:29 Найти цитируемый пост)
If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

Может, но не обязательно приведёт.
С другой стороны, если "an error occurs", то схему лучше переделать. Хотя, честно говоря, не понимаю, какая именно возникает ошибка. То, что неправильное применение критических секций может вызвать взаимную блокировку, несомненно.


Цитата(GremlinProg @  14.3.2012,  13:29 Найти цитируемый пост)
не надо пытаться думать о том, что какой-то поток дожен отработать раньше другого, это движение мыслей неправильное,
и приведет лишь к потерям времени, денег, нервов

Интересное замечание)))
Но в данном случае это требуется по условию задачи.
Если будет такая возможность и желание, предложите свою схему, переделаем smile 


Цитата(wallstreet @  14.3.2012,  12:08 Найти цитируемый пост)
Примного благодарствую) 

На здоровье)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 14.3.2012, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(feodorv @  14.3.2012,  20:26 Найти цитируемый пост)
Хотя, честно говоря, не понимаю, какая именно возникает ошибка.

Кажется, всё же, понимаю)))
При отсутствии цикла в Thread1 всё было бы нормально. При наличии цикла возможно его зависание... Мдя)))

Это сообщение отредактировал(а) feodorv - 15.3.2012, 02:18


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
GremlinProg
Дата 15.3.2012, 06:55 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  14.3.2012,  21:26 Найти цитируемый пост)
Ок. Скажу иначе: потоку, захватившему критическую секцию, не передаются права владения ею (в отличии от мютекса). 

угу
Цитата(feodorv @  14.3.2012,  21:26 Найти цитируемый пост)
То, что неправильное применение критических секций может вызвать взаимную блокировку, несомненно.

угу + включаем законы мерфи
Цитата(feodorv @  14.3.2012,  21:26 Найти цитируемый пост)
Но в данном случае это требуется по условию задачи.

по условию задачи, очередность отработки потоков не регламентируется )
Цитата(feodorv @  14.3.2012,  21:26 Найти цитируемый пост)
предложите свою схему

1. заводим секцию x, охраняющую модификацию/чтение массива
2. заводим событие (или семафор) y, разрешающий перезапись данных массива
3. заводим событие (или семафор) z, разрешающий отрисовку данных массива

4. заводим поток a, который ресайзит массив (с учетом входа в x) и сигнализирует y
5. заводим поток b, который при активации y заполняет массив (с учетом входа в x) и сигнализирует z
6. заводим поток c, который при активации z рисует массив во временный растр (с учетом входа в x) и посылает команду на обновление окна
7. в WM_PAINT просто отрисовать готовый растр, если он имеется

6 и 7 пункт, по хорошему, требует также синхронизации доступа к глобальному растру, решать это можно как секцией, так и простой взаимоблокировкой,

p.s.: если не понятно как реализовать синхронизацию доступа к глобальному растру взаимоблокировкой, могу потом показать

Добавлено через 8 минут и 10 секунд
+ для большей интерактивности,
на форме можно, разместить манипуляторы, управляющие первым потоком, например: для управления длиной массива и кнопкой, для "спуска" итерации первого потока, тогда потребуется еще одно событие, которого этот поток будет ожидать, перед ресайзом массива и, соответственно, которое будет сигнализировать кнопка


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 15.3.2012, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  15.3.2012,  07:55 Найти цитируемый пост)
+ включаем законы мерфи

Они всегда включены))) Но если жить только по ним, то лучше не жить)))


Цитата(GremlinProg @  15.3.2012,  07:55 Найти цитируемый пост)
по условию задачи, очередность отработки потоков не регламентируется )

Да, согласен. Просто есть желательная последовательность выполнения потоков (согласитесь, странно планировать программу так, чтобы пробуждались потоки в обратной последовательности, то есть сначала пробуждать поток с отрисовкой, потом пробуждать поток с инициализацией, и только потом с выделением памяти). Понятно, что реализовывать программу нужно исходя из того, что порядок выполнения и планирование потоков операцинной состемой может быть произвольными (с нашей, пользовательской, точки зрения). Это решает ОС.


Цитата(GremlinProg @  15.3.2012,  07:55 Найти цитируемый пост)
7. в WM_PAINT просто отрисовать готовый растр, если он имеется

Ок. 
А метафайл никак подойдёт под эту задачу?


Цитата(GremlinProg @  15.3.2012,  07:55 Найти цитируемый пост)
p.s.: если не понятно как реализовать синхронизацию доступа к глобальному растру взаимоблокировкой, могу потом показать

Не понятно, что здесь непонятного, поэтому лучше показать, чтобы рассеять все сомнения))))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
GremlinProg
Дата 16.3.2012, 07:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  15.3.2012,  18:03 Найти цитируемый пост)
Они всегда включены))) Но если жить только по ним, то лучше не жить)))

smile 
судя по твоему обширному плану, они выключены,

эти законы не для того, чтобы жить по ним,
а для того, чтобы не заморачиваться, и жить по своим smile
Цитата(feodorv @  15.3.2012,  18:03 Найти цитируемый пост)
согласитесь, странно планировать программу так, чтобы пробуждались потоки в обратной последовательности, то есть сначала пробуждать поток с отрисовкой, потом пробуждать поток с инициализацией, и только потом с выделением памяти

а процесс разработок - такая штука: чем дальше в лес, тем больше дров - не всегда может опираться на "желательную" логику работы программы,
особенно тогда, когда эта логика нестабильна и может быть легко нарушена


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
GremlinProg
Дата 16.3.2012, 07:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  15.3.2012,  18:03 Найти цитируемый пост)
А метафайл никак подойдёт под эту задачу?

если я правильно понимаю: emf, wmf?

подойдет, конечно,
только пользы от него конкретно в данной задаче будет 0,
поскольку отрисовка такого файла будет идти не в потоке, а все в том же WM_PAINT (в потоке будет просто сформирован набор команд)

лучше всего подойдет простой растр


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 16.3.2012, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  16.3.2012,  08:06 Найти цитируемый пост)
судя по твоему обширному плану

План не обширный, а всего лишь подробный)))

Цитата(GremlinProg @  16.3.2012,  08:06 Найти цитируемый пост)
эти законы не для того, чтобы жить по ним, а для того, чтобы 

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

Цитата(GremlinProg @  16.3.2012,  08:26 Найти цитируемый пост)
лучше всего подойдет простой растр

Ок!
Плохо, что автор темы пропал куда-то...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 22.3.2012, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Цитата

6 и 7 пункт, по хорошему, требует также синхронизации доступа к глобальному растру, решать это можно как секцией, так и простой взаимоблокировкой,

p.s.: если не понятно как реализовать синхронизацию доступа к глобальному растру взаимоблокировкой, могу потом показать


Честно признаться не знаю как сформировать мой массив в виде растового изображения. Поэтому без вашей помощи буду месяц разбираться((


Цитата

Плохо, что автор темы пропал куда-то... 


ну почему же пропал, просто времени мало в последнее время на самообучение(((
а так процесс идет!! ;)

Это сообщение отредактировал(а) wallstreet - 22.3.2012, 13:11
PM MAIL   Вверх
GremlinProg
Дата 22.3.2012, 14:58 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  22.3.2012,  15:09 Найти цитируемый пост)
Честно признаться не знаю как сформировать мой массив в виде растового изображения. Поэтому без вашей помощи буду месяц разбираться((

Код

hScreenDC = ::GetDC( HWND_DESKTOP );
hMemDC = ::CreateCompatibleDC( hScreenDC );
hMemBitmap = ::CreateCompatibleBitmap( hScreenDC, Width, Height );
::ReleaseDC( HWND_DESKTOP, hdcScreen );
hMemBitmap = ::SelectObject( hMemDC, hMemBitmap );
//
PaintArray( hMemDC );
//
hMemBitmap = ::SelectObject( hMemDC, hMemBitmap );
::DeleteDC( hMemDC );


Width, Height - размерв растра
PaintArray - метод отрисовки растра
hMemBitmap - сам растр

p.s.:код писал в браузере, контроль ошибок не вел


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 27.3.2012, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Благодарю за ответ, но  вопросов появилось еще больше((
Правильно ли я понимаю, что:
Код

hScreenDC = ::GetDC( HWND_DESKTOP ); //получаем дескриптор контекста рабочего стола

т.е. фактически делаем PrintScreen экрана?
Код

hMemDC = ::CreateCompatibleDC( hScreenDC ); // насколько я понимаю с помощью этой функции
                        // создают контекст загруженного изображения, а
                        // у нас только дескриптор но не могу понять чего.
                        // hScreenDC ведь не дескриптор контекста изображения
                        // пока что. Или ошибаюсь?

hMemBitmap = ::CreateCompatibleBitmap( hScreenDC, Width, Height ); // получаем адрес структуры изображения
                                                         // BITMAP. Изображения рабочего стола?
::ReleaseDC( HWND_DESKTOP, hdcScreen );                   // Освобождаем контекст
hMemBitmap = ::SelectObject( hMemDC, hMemBitmap ); // выбираем объект hMemBitmap в контекст hMemDC

По поводу метода отрисовки растра. Честно говоря у меня вообще ни одной мысли нет как я могу это сделать. Думал что растовая графика работает исключительно с имеющимися уже изображениями. А как создавать изображение ума не приложу. Т.е. насколько я понимаю растовая графика это просто разложение по пикселам изображения. А вот как превратить текст или число в изображение не могу даже представить. Тем более не могу понять зачем нам принт скрин рабочего стола(((( Короче в голове каша полная.. Огромная просьба разъясните что к чему.

Это сообщение отредактировал(а) wallstreet - 27.3.2012, 16:31
PM MAIL   Вверх
GremlinProg
Дата 28.3.2012, 07:23 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  27.3.2012,  18:29 Найти цитируемый пост)
т.е. фактически делаем PrintScreen экрана?

нет, фактически - "получаем вожжи" для его управления,
но в данном случае нам он нужен только для того, чтобы создать растр, который имеет с ним аналогичные характеристики,
чтобы его можно было отобразить на экране
Цитата(wallstreet @  27.3.2012,  18:29 Найти цитируемый пост)

// насколько я понимаю с помощью этой функции
// создают контекст загруженного изображения, а
// у нас только дескриптор но не могу понять чего.
// hScreenDC ведь не дескриптор контекста изображения
// пока что. Или ошибаюсь?

с помощью этой функции создают контекст изображения, совместимый с заданным, т.е. имеющий с ним совместимый формат
Цитата(wallstreet @  27.3.2012,  18:29 Найти цитируемый пост)

//получаем адрес структуры изображения
// BITMAP. Изображения рабочего стола?

с помощью этой функции создают растр, совместимый с заданным контекстом,
т.е. имеющий с ним совместимый формат,
т.е. растр, который можно выбрать и манипулировать им в аналогичном контексте
Цитата(wallstreet @  27.3.2012,  18:29 Найти цитируемый пост)
По поводу метода отрисовки растра. Честно говоря у меня вообще ни одной мысли нет как я могу это сделать

ты это уже сделал (см. первый пост): цикл с TextOut,
просто вместо hdc нужно указать hMemDC


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 30.3.2012, 00:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Вобщем сделал первый очень сырой вариант без таймера. 
Основная задача для меня была сделать управление и научиться создавать растр. Ну и выводить его на экран когда надо.
Не со всем удалось справиться, далеко не со всем.
Итак вопросы:
1) Не могу понять почему после запуска всех потоков по очереди, в конце третьего не срабатывает InvalidateRect()
Т.е. картинка создается, но не отображается. Стоит хоть чуть чуть изменить размеры окна, как она сразу отрисовывается.
2) Где нужно удалять массив, что бы при увеличении его размера не было выхода за пределы.
Когда в скроллбаре выбираю размерность 10 к примеру, соответственно отрисуется массив 10х10, если после этого
выбираю меньшую размерность все норм, но если большую, то сразу же работа прерывается.
3) массив нормально заполняется размерностью 10х10 если поставить больше, то начинают отображаться символы.
По всей видимости где-то что-то не расчитал с типом данных(((( Так вот если подскажите где, буду признателен очень!


Вот собственно ссылка на файл
сырой проект


Заранее благодарю за помощь в обучении.
PM MAIL   Вверх
GremlinProg
Дата 30.3.2012, 09:28 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



1. возвращаемся в самое начало:
Цитата(feodorv @  12.3.2012,  01:08 Найти цитируемый пост)
В коде этого нет. Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся.

2. булева переменная x_section лишняя, надо избавиться, главный вопрос: где критическая секция x (CRITICAL_SECTION), и зачем здесь hSemaphoreX, видимо тут уже путаница
3. семафоры, которые ожидают потоки не нужно снова включать из этих же потоков, вызывая для них ReleaseSemaphore, их всегда должно включать что-то внешнее:
 - a включает кнопка (основной поток)
 - y включает поток 1
 - z включает поток 2

ну, раз появилась кнопка, значит здесь a - это тот самый синхронизатор, который включает первый поток a, вместо непонятного hSemaphoreX
(на данном этапе это не так важно из-за первых двух ошибок)
4. Thread1 не перераспределяет память buf, он только создает массив (на данном этапе это не важно из-за первых двух ошибок), вобщем-то напрямую память трогать не обязательно, можно использовать какой-нибудь готовый контейнер, STL, например, std::vector
5. после отрисовки растра в потоке не вижу его обратной выборки из HDC и не вижу удаления HDC, если этого не делать будет утечка GDI-ресурсов и hMemBitmap будет хранить системный растр, а не тот, который рисуешь
6. hMemDC на WM_PAINT нужно создать свой, по той же схеме
7. hMemBitmap в таком случае требует синхронизации доступа из основного и 2-го потоков
8. не надо делать глобальными hScreenDC, hMemDC, hMemBitmap (не стоит), глобальным можно сделать например hMemBitmap, или просто другой HBITMAP, чтобы не делать ошибок на пустом месте
9. соответственно, не видно работы с критической секцией (ну раз ее нет, значит и не видно, но не видно даже попыток снхронизировать доступ к массиву)

Цитата(wallstreet @  30.3.2012,  02:06 Найти цитируемый пост)
Не могу понять почему после запуска всех потоков по очереди, в конце третьего не срабатывает InvalidateRect()

InvalidateRect срабатывает, см. п. 5
Цитата(wallstreet @  30.3.2012,  02:06 Найти цитируемый пост)
Стоит хоть чуть чуть изменить размеры окна, как она сразу отрисовывается.

это будет происходить через раз (с учетом исправления п.1), т.к. в HDC чередуется выборка hMemBitmap, см. п. 5
Цитата(wallstreet @  30.3.2012,  02:06 Найти цитируемый пост)
Где нужно удалять массив, что бы при увеличении его размера не было выхода за пределы

в потоке 1, он же занимается изменением размера массива
Цитата(wallstreet @  30.3.2012,  02:06 Найти цитируемый пост)
если после этого выбираю меньшую размерность все норм, но если большую, то сразу же работа прерывается.

все что после этого, уже не имеет значения, т.к. потоков уже нет, см. п.1
Цитата(wallstreet @  30.3.2012,  02:06 Найти цитируемый пост)
массив нормально заполняется размерностью 10х10 если поставить больше, то начинают отображаться символы.

пока так же не имеет значения, см. п.1


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 4.4.2012, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



мое незнание как реализовать ваши советы, завели меня в тупик.((
Но все по порядку:
Цитата

1. возвращаемся в самое начало:

Цитата(feodorv @  12.3.2012,  01:08 )
В коде этого нет. Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся.

Не могу понять как зациклить все потоки что бы они отрабатывали не один раз? Т.е. по срабатываюнию кнопки я освобождаю семафорХ, потом первый освобождает семафорУ, второй освобождает семафорZ а тот в свою очередь опять освобождает семафорХ или каким-то образом необходимо запускать поток через _beginthreadex()?

2. убрал булева переменную x_section (лепил горбатого к стенке, сам не понимаю зачем) Сейчас все потоки с первого по третий защитил критической секцией, для синхронизированной работы с непосредственной отрисовкой в WM_PAINT, которую тоже защищаю критической секцией. Все остальные потоки будут гарантированно выполняться в нужной последовательности за счет последовательного освобождения семафоров.
Цитата

и зачем здесь hSemaphoreX, видимо тут уже путаница

А как тогда я зациклю потоки что бы они не отображались всего один раз?

3. Те же вопросы с зацикливанием потоков.. Я просто не знаю, как это сделать, не понимаю принцип(.

4. Если делать с вектором то чем тогда займется первый поток ведь он, вектор, должен быть глобальным?

5. Пытаюсь делать так:

Код

hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);
::DeleteDC(hMemDC);


а растр вообще перестает отрисовываться. Кстати советуют удалять дескрптор контекста, который
создавался функцией GetDC(), с помощью ReleaseDC(). Так вот Вы специально выбрали первый вариант (DeleteDC)? Если 
нет, то какой хендл (первый аргумент в ReleaseDC) использовать?

6. Вот что у меня получилось:
Код

case WM_PAINT:
        hScreenDC = ::GetDC(HWND_DESKTOP);
        hMemDC = CreateCompatibleDC(hScreenDC);
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);
        hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);
        hdc = BeginPaint(hWnd, &ps);
        EnterCriticalSection(&cs);
        BitBlt(hdc, 0, 0, cx, cy, hMemDC, 0, 0, NOTSRCCOPY); // Отрисовываем раст
        LeaveCriticalSection(&cs);
        EndPaint(hWnd, &ps);
        break;


Опять же понять не могу, как он отрисует раст, если он тут еще не нарисован?!?!?! Ведь я же удалил дескриптор контекста растра еще в 3м потоке.

7. 
Цитата

hMemBitmap в таком случае требует синхронизации доступа из основного и 2-го потоков

а синхронизировать что конкретно, отрисовку? Т.е. пока создаем растр, не допускать к отрисовке в WM_PAINT?
В данном случае я оградил от отрисовки все потки критической секцией, т.е. отрисовка не начнется пока все не закончат свою работу.

8. Так и поступил, только если сделать hMemBitmap типа BITMAP то будут проблемы вот тут: 
Код

hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);

поэтому она у меня HGDIOBJ типа. 

9. Вроде бы сейчас попытался  smile  


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

Ссылка на проект

Это сообщение отредактировал(а) wallstreet - 4.4.2012, 00:18
PM MAIL   Вверх
GremlinProg
Дата 4.4.2012, 07:11 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
Не могу понять как зациклить все потоки что бы они отрабатывали не один раз?

надо просто завести в потоках цикл (пусть он пока будет бесконечный):
Код

unsigned _stdcall Thread1(void *param){
  for( ; ; ){
    ::WaitForSingleObject( ... );
    ...
  }
}

потом можно будет его ограничить глобальным событием hAbort, чтобы по его включении все потоки спокойно завершали свою работу
Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
в WM_PAINT, которую тоже защищаю критической секцией

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

пока я бы не рекомендовал защищать WM_PAINT, это пока не такая страшная ошибка

Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
А как тогда я зациклю потоки что бы они не отображались всего один раз?

циклом во всех потоках(см. выше)
Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
Если делать с вектором то чем тогда займется первый поток ведь он, вектор, должен быть глобальным?

пусть вектор будет глобальным, в чем проблема?
Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
а растр вообще перестает отрисовываться.

в старом коде ты использовал в WM_PAINT HDC, созданный в потоке, поэтому растр и не рисуется,
в WM_PAINT нужно создать свой HDC и выбрать в него битмап (в 6 почти все правильно, только ты забыл обратно выбрать растр и освободить контекст, т.е. тут сохраняется ошибка п.5)

Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
Кстати советуют удалять дескрптор контекста, которыйсоздавался функцией GetDC(), с помощью ReleaseDC()

конечно
Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
Так вот Вы специально выбрали первый вариант (DeleteDC)? Если нет, то какой хендл (первый аргумент в ReleaseDC) использовать?

не понял  smile 
у меня для GetDC вызывается ReleaseDC, и в первом параметре тот же дескриптор, что и в первом параметре GetDC, т.е. HWND_DESKTOP или NULL, т.е. - "экран",
DeleteDC вызывается только для CreateCompatibleDC
Цитата(wallstreet @  4.4.2012,  02:09 Найти цитируемый пост)
Опять же понять не могу, как он отрисует раст, если он тут еще не нарисован?!?!?! Ведь я же удалил дескриптор контекста растра еще в 3м потоке.

путаешь,
ты удалил не растр, а контекст hMemDC, это разные вещи,
растр находится в hMemBitmap

по хорошему, как я уже говорил, следует синхронизировать обращение к hMemBitmap (но другим синхронизатором),
у тебя в этом плане тут 2 ошибки:
1. синхронизируется только вызов BitBlt, хотя 3-й поток может изменить растр еще на этапе SelectObject
2. в 3-м потоке используется та же переменная, что и в основном, на WM_PAINT - это hMemBitmap (да, в 8 ты об этом правильно подметил), т.е. это означает, что пока 3-й поток рисует массив, доступ к этой переменной должен быть блокирован, поэтому я и рекомендую вместо глобальной hMemBitmap использовать какую-нить другую, например: hMemSharedBitmap, в которую 3-й поток, после завершения отрисовки массива, будет копировать hMemBitmap, и которую будет использовать основной поток в WM_PAINT, вот доступ к этой переменной и надо синхронизировать

ну, и теперь, когда ты зациклишь все потоки, потребуется удалять hMemSharedBitmap, перед очередным ее обновлением в 3-м потоке, чтобы не было утечки GDI-ресурсов, для этого нужно вначале инициироввать ее в значение NULL, и перед любой модификацией проверить на NULL и удалить, в случае, если она не NULL с помощью функции DeleteObject

p.s.: неблагодарное это дело, пальцев не хватит, проще написать код,
feodorv, не желаешь присоединиться?
ты же можешь, я знаю  smile 


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 4.4.2012, 16:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Делаю вот так:
Поток3
Код

HGDIOBJ hMemSharedBitmap;
unsigned _stdcall Thread3(void *param)
{
    HDC hScreenDC, hMemDC;
    HGDIOBJ hMemBitmap;
    int x = 0;
    int y = 0;
    hMemSharedBitmap = NULL;

    while(!done)
    {
        WaitForSingleObject(hSemaphoreZ, INFINITE);
        if(done)
            break;
        hScreenDC = ::GetDC(HWND_DESKTOP);                              // Получаем указатель на контекст рабочего стола
        hMemDC = CreateCompatibleDC(hScreenDC);                         // Создаем в памяти контекст устройства совместимый с hScreenDC
        hMemBitmap = CreateCompatibleBitmap(hScreenDC, cx, cy);         // Инициализируем битовый образ делая его совместимым с hScreenDC
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);                           // Удаляем контекст hScreenDC
        hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);                // Выбираем объект для контекста hMemDC
    
        // Рисуем растр
        for(int count_row=0; count_row<::scrlh; count_row++)
        {
            for(int count_column=0; count_column<::scrlh; count_column++)
            {
                y=count_row*30;
                x=count_column*30;
                _itot(buf[count_row][count_column], str, ::scrlh);
                TextOut(hMemDC, x, y, str, _tcslen(str));
            }
        }
        if(hMemSharedBitmap=NULL)                                        
        {
            hMemSharedBitmap = CreateCompatibleBitmap(hMemDC, cx, cy);   // Инициализируем битовый образ делая его совместимым с hMemDC
        }
        else 
        {
            DeleteObject(hMemSharedBitmap);
        }
        InvalidateRect((HWND)param, FALSE, TRUE);                        // Перерисовываем окно
        LeaveCriticalSection(&cs);                                       // Освобождаем критическую секцию
        ::DeleteDC(hMemDC);                                              // Удаляем дескриптор контекста
    }
    return 0;
}


Отрисовка данных:
Код

case WM_PAINT:
        hScreenDC = ::GetDC(HWND_DESKTOP);                              // Получаем указатель на контекст рабочего стола
        hMemDC = CreateCompatibleDC(hScreenDC);                         // Создаем в памяти контекст устройства совместимый с hScreenDC
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);                           // Удаляем контекст hScreenDC
        hMemSharedBitmap = ::SelectObject(hMemDC, hMemSharedBitmap);    // Выбираем объект для контекста hMemDC
     
        hdc = BeginPaint(hWnd, &ps);
        EnterCriticalSection(&cs);
        BitBlt(hdc, 0, 0, cx, cy, hMemDC, 0, 0, NOTSRCCOPY);             // Отрисовываем раст
        LeaveCriticalSection(&cs);
        EndPaint(hWnd, &ps);

        ::DeleteDC(hMemDC);                                              // Удаляем контекст hMemDC
        break;


Где в части создания и отрисовки растра я допускаю ошибку?

Проект

Это сообщение отредактировал(а) wallstreet - 4.4.2012, 16:16
PM MAIL   Вверх
GremlinProg
Дата 5.4.2012, 06:51 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



установка и использование hMemSharedBitmap неправильная,
не надо для нее создавать растр (CreateCompatibleBitmap),
ей надо просто присвоить значение hMemBitmap:
Цитата(wallstreet @ 4.4.2012,  18:00)

HGDIOBJ hMemSharedBitmap;
unsigned _stdcall Thread3(void *param)
{
    HDC hScreenDC, hMemDC;
    HGDIOBJ hMemBitmap;
    int x = 0;
    int y = 0;
    hMemSharedBitmap = NULL;

    while(!done)
    {
        WaitForSingleObject(hSemaphoreZ, INFINITE);
        if(done)
            break;
        hScreenDC = ::GetDC(HWND_DESKTOP);                              // Получаем указатель на контекст рабочего стола
        hMemDC = CreateCompatibleDC(hScreenDC);                         // Создаем в памяти контекст устройства совместимый с hScreenDC
        hMemBitmap = CreateCompatibleBitmap(hScreenDC, cx, cy);         // Инициализируем битовый образ делая его совместимым с hScreenDC
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);                           // Удаляем контекст hScreenDC
        hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);                // Выбираем объект для контекста hMemDC
    
        // Рисуем растр
        Enter( x );
        for(int count_row=0; count_row<::scrlh; count_row++)
        {
            for(int count_column=0; count_column<::scrlh; count_column++)
            {
                y=count_row*30;
                x=count_column*30;
                _itot(buf[count_row][count_column], str, ::scrlh);
                TextOut(hMemDC, x, y, str, _tcslen(str));
            }
        }
        Leave( x );
        hMemBitmap = ::SelectObject(hMemDC, hMemBitmap);                // Выбираем растр обратно из hMemDC!!!!!!!!!!

        ::DeleteDC(hMemDC);                                              // Удаляем дескриптор контекста
        if(hMemSharedBitmap=NULL)                                        
        {
            hMemSharedBitmap = CreateCompatibleBitmap(hMemDC, cx, cy);   // Инициализируем битовый образ делая его совместимым с hMemDC
        }
        else 
        {
            DeleteObject(hMemSharedBitmap);
        }
        LeaveCriticalSection(&cs);                                       // Освобождаем критическую секцию

        Enter( shared );
        if( hMemSharedBitmap ){
            ::DeleteObject( hMemSharedBitmap );
        }
        hMemSharedBitmap = hMemBitmap;
        Leave( shared );

        InvalidateRect((HWND)param, FALSE, TRUE);                        // Перерисовываем окно
    }
    return 0;
}

Цитата(wallstreet @ 4.4.2012,  18:00)

case WM_PAINT:
        hScreenDC = ::GetDC(HWND_DESKTOP);                              // Получаем указатель на контекст рабочего стола
        hMemDC = CreateCompatibleDC(hScreenDC);                         // Создаем в памяти контекст устройства совместимый с hScreenDC
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);                           // Удаляем контекст hScreenDC
        Enter( shared );
        hMemSharedBitmap = ::SelectObject(hMemDC, hMemSharedBitmap);    // Выбираем объект для контекста hMemDC
     
        hdc = BeginPaint(hWnd, &ps);
        EnterCriticalSection(&cs);
        BitBlt(hdc, 0, 0, cx, cy, hMemDC, 0, 0, NOTSRCCOPY);             // Отрисовываем раст
        LeaveCriticalSection(&cs);
        EndPaint(hWnd, &ps);
        hMemSharedBitmap = ::SelectObject(hMemDC, hMemSharedBitmap);    // Выбираем растр обратно из hMemDC!!!!!!!!!!!!!!!!!!!!!
        Leave( shared );

        ::DeleteDC(hMemDC);                                              // Удаляем контекст hMemDC
        break;

Enter и Leave здесь, соответственно, вход и выход из эксклюзивного участка кода,
x и shared - сами синхронизаторы: x - защищает модификацию и чтение массива, а shared защишает доступ к переменной hMemSharedBitmap


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 5.4.2012, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  4.4.2012,  08:11 Найти цитируемый пост)
feodorv, не желаешь присоединиться?

Прошу прощения, что ушёл с сумрак, дела зовут...

GremlinProg
Правки супер! То, что надо)))

Только два момента, замеченных при беглом просмотре:
1/ что такое cx и cy в Thread3 и в WM_PAINT? Как я понимаю, в Thread3 мы должны высчитывать размер битмапа исходя из начальных данных (то есть buf[count_row][count_column] должен порождать cx и cy путём подсчёта места, необходимого под TextOut... Если же сx и cy высчитывать исходя из размера окна, то при ресайзе этого самого окна могут возникнуть неприятные артефакты.
2/ рисовать стОит только тогда, когда hMemSharedBitmap не NULL.


wallstreet
Очень прошу обратить внимание на
Цитата(GremlinProg @  5.4.2012,  07:51 Найти цитируемый пост)
x и shared - сами синхронизаторы: x - защищает модификацию и чтение массива, а shared защишает доступ к переменной hMemSharedBitmap 

То есть нужны 2 критические секции, а не одна: x - синхронизирует доступ к buf в Thread1, Thread2, Thread3, а shared - к hMemSharedBitmap в Thread3 и WM_PAINT основного потока.

Ну и опять же, хочется весь проект с правками...


Это сообщение отредактировал(а) feodorv - 5.4.2012, 11:17


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 6.4.2012, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Всем доброго дня.
Благодарю за разъяснения, теперь ясно как никогда.
Подровнял я проект под ваши советы, даже вектор прикрутил. Но следуя сложившейся традиции
где-то что-то напортачил и матрица отображается криво. А точнее одна ее строка только ито не с самого начала.
Что касается:
Цитата

1/ что такое cx и cy в Thread3 и в WM_PAINT? Как я понимаю, в Thread3 мы должны высчитывать размер битмапа исходя из начальных данных (то есть buf[count_row][count_column] должен порождать cx и cy путём подсчёта места, необходимого под TextOut...

я инициализировал переменные ширины и высоты битмапа значением выбраным пользователем в скроллбаре
умноженным на 30 (ширина между цифрами в битмапе в пикселях) при нажатии кнопки "ОК".
Выглядело это вот так:
Код

::cx = scrlh * 30;
::cy = scrlh * 30;

но можно задать высоту и ширину во втором потоке, сразу после заполнения матрицы значениями.
вот так:
Код

::cx = vv.size() * 30;
::cy = vv.size() * 30;



Благодарю за участие, 
вот, собственно, ссылка для скачивания проекта: Ссылка на проект

Это сообщение отредактировал(а) wallstreet - 6.4.2012, 18:30
PM MAIL   Вверх
feodorv
Дата 8.4.2012, 17:48 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(wallstreet @  6.4.2012,  14:50 Найти цитируемый пост)
вот, собственно, ссылка для скачивания проекта

Посмотрел код одним глазом и... ужаснулся(((
Как же можно допускать такое нагромождение операторов, переменных...

Цитата(wallstreet @  6.4.2012,  14:50 Найти цитируемый пост)
одна ее строка только ито не с самого начала.

Про начало не знаю, но то, что одна строка:
Код

        // Рисуем растр
        int count_row = 0;
        int count_column = 0;
        for(itVv=vv.begin(); itVv!=vv.end(); itVv++, count_row++)
        {
            for(itV=itVv->begin(); itV!=itVv->end(); itV++, count_column++)
            {
                y=count_row*30;
                x=count_column*30;
                _itot(*itV, str, vv.size());
                TextOut(hMemDC, x, y, str, _tcslen(str));
            }
        }

Ну как минимум count_column во втором форе нужно переинициализировать в 0. Вообще, все векторные прибомбасы стоило отложить на самый конец, имхо.
Как максимум нужно разобраться с итераторами (что выводит TextOut?).

По замечаниям:

1/ мы с GremlinProg договорились не использовать грязных трюков с захватом критической секции в одном потоке и освобождением в другом. Надо исправить smile 

2/ откуда взялась и что защищает критическая секция csX?

3/ cx и cy - есть характеристики битмапа hMemSharedBitmap. Менять их нужно только в тот момент, в который изменяется значение hMemSharedBitmap, а не в любой произвольный момент. Переменные hMemSharedBitmap, cx, cy защищаются критической секцией csShared.
Соответственно, ::scrlh - есть характеристика вектора (в прошлом - буфера), менять значение этой переменной стоит тогда, когда мы изменяем размер вектора (или буфера). Вектор и ::scrlh защищаются критической секцией cs.

4/ Что делает этот код:
Код

unsigned _stdcall Thread3(void *param)
{
 ...
    [color=red]hMemSharedBitmap = NULL;[/color]
...
}

???

5/ таймер больше не используется?

6/ какое отношение имеет инициализация семафоров и запуск потоков к Dialog1??? Что будет, если Dialog1 вызвать более одного раза? Сколько будет потоков? Сколько семафоров? Зачем InvalidateRect(hDlg, FALSE, TRUE); в Dialog1() при WM_COMMAND IDOK?

7/ зачем нам теперь глобальные переменные 
Код

TCHAR str[10];
int **buf;
int x, y,
HGDIOBJ hMemBitmap;


8/ зачем семафоры, когда хорошо жили при событиях?

Чего-то я ещё заметил, но уже забыл....

Это сообщение отредактировал(а) feodorv - 8.4.2012, 18:16


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 9.4.2012, 22:09 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Цитата

Посмотрел код одним глазом и... ужаснулся(((
Как же можно допускать такое нагромождение операторов, переменных...


Ну так еще бы, проект сырой очень, да и вообще)
На самом деле постоянно что-то меняю что-то пробую, поэтому и переменных куча ненужных.
Вобщем впреть постараюсь сразу удалять. Хорошее замечание!

Цитата

Ну как минимум count_column во втором форе нужно переинициализировать в 0. Вообще, все векторные прибомбасы стоило отложить на самый конец, имхо.
Как максимум нужно разобраться с итераторами (что выводит TextOut?).


Да, точно. Теперь матрица заполняется правильно, но неправильными числами. (сейчас я изменил заполнение на рендомное)
А с чем конкретно в итераторах? Я неправильно с ними работаю? Пробовал в консоле данную структуру создания и вывода, все работало как часы. 

1/ ОК. Убрал секцию cs, только теперь смущает, что первый поток, который по идее должен был заниматься выделением памяти под данные, не занимается ничем. Ну да ладно..

2/ сsX - защищает модификацию и чтение вектора

3/ 
Цитата

cx и cy - есть характеристики битмапа hMemSharedBitmap. Менять их нужно только в тот момент, в который изменяется значение hMemSharedBitmap, а не в любой произвольный момент. Переменные hMemSharedBitmap, cx, cy защищаются критической секцией csShared.

Если я инициализирую значения сх и су в потоке3, в секции csShared то растр не отрисовывается в WM_PAINT.
Цитата

::scrlh - есть характеристика вектора (в прошлом - буфера), менять значение этой переменной стоит тогда, когда мы изменяем размер вектора (или буфера). Вектор и ::scrlh защищаются критической секцией cs.

Значение переменной ::scrlh  изменяет локальная переменная scrlh диалога1 на значение выбранное скроллбаром в обработке нажатия кнопки "ОК". Собственно оную нажав мы и изменяем исходные параметры размерности моего вектора и растра. Т.е. мы открыли диалог1, выбрали размерность матрицы, нажали "ОК" и матрица должна сразу же поменять размер и перерисоваться на главном окне. Именно поэтому, как мне казалось, правильнее было прилепить запуск потоков к обрабоке нажатия кнопки ОК, что я и делал, но вопрос с Таймером для меня был открыт. Вобщем, если с потоками все понятно, то как изменить значение переменной ::scrlh  в потоке2, для меня загадка?!?! В принципе можно создать еще одну переменную, локальную для потока2 и брать значение глобальной ::scrlh, но есть ли в этом смысл?

4/ Честно признаться не помню уже какую цель преследовал, но явно над чем-то эксперементировал методом тыка)

5/ Таймер будет скоро. Если не сложно, подскажите как я могу его запускать из диалога1 и где его устанавливать, т.к. он запускает потоки, а они у меня запускаются при создании окна и второй раз их запускать таймером будет неправильно. 

6/ Ну основную логику описал в п. 3. Просто думал так, что запуск потоков с созданием и отрисовкой матрицы необходимо делать после того как пользователь определится с ее размером, а самым лучшим для этого подтверждением является нажатие на кнопку "ОК". Сейчас то, с вашей помощью, я уже понял как можно по другому (страшно сказать правильно smile ).

7/ Удалил ненужные, а вот hMemBitmap очень даже нужная. Это наш растр, который мы создаем в потоке2, а в потке3 инициализируем им hMemSharedBitmap. Однако в глобале ей делать нечего и это факт)

8/ Ну моя цель работы над данным проектом это учеба. С сбытиями разобрался, теперь представилась возможность попрактиковаться с семафорами. Почему бы и нет smile


Ссылка на проект тут -> обновленный вариант

Это сообщение отредактировал(а) wallstreet - 10.4.2012, 10:09
PM MAIL   Вверх
wallstreet
Дата 11.4.2012, 17:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Вот я прописал таймер.
Он у меня создается в момент создания окна. Создается без задержек и сразу же запускает потоки, но потоки не отрисовывают раст, т.к. семафорХ не запущен. Этот семафор освободит диалог1 после того как пользователь определится с размерностью матрицы, которую хочет видеть на экране и нажмет кнопку "ОК". 
Предположим пользователь сидит и смотрит на пустое окно и размерность массива не выбирает, даже диалог1 не открывает. Так вот мне интересно, в этот момент мой таймер что делает, создает раз в секунду поток, который ожидает освобождения семафораХ? 
Так вот вопросы эти появляются только потому, что после того как я определю размерность матрицы в диалоге1 программа отрисует один раз мой растр и все. Да еще и непонятно почему заполняет только матрицу 10х10 правильно, а при заполнении 5х5, к примеру, то будет она выглядеть вот так:
user posted image
хотя должен был начинаться второй ряд с 5 6 7 8 9, ну и тд.
И что самое главное картинка не перерисовывается с новой матрицей, хотя вроде и цикл есть в потоках, но не хочет. Почему?(



Ссылка на проект тут=>проект
Заранее благодарю за ответы!

Это сообщение отредактировал(а) wallstreet - 11.4.2012, 17:45
PM MAIL   Вверх
GremlinProg
Дата 12.4.2012, 07:34 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  11.4.2012,  19:38 Найти цитируемый пост)
Вот я прописал таймер.Он у меня создается в момент создания окна. Создается без задержек и сразу же запускает потоки, но потоки не отрисовывают раст, т.к. семафорХ не запущен. Этот семафор освободит диалог1 после того как пользователь определится с размерностью матрицы, которую хочет видеть на экране и нажмет кнопку "ОК". 

таймер должен заменить семафорХ, а не дополнить,
просто удали семафорХ,

диалог теперь не должен запускать поток, т.к. он запускается таймером,
но возникает еще один конфликт, подобный hSharedBitmap: переменная scrlh в таком случае тоже должна быть защищена из диалога и в потоках

теперь по коду:
1. у тебя опять путаница в ролях потоков: зачем первый поток очищает массив, когда он должен задавать его размер?
2. ладно, очищает, но почему без синхронизации?
3. "ЗАПОЛНЕНИЕ ВЕКТОРА" ну сам же пишешь: "ЗАПОЛНЕНИЕ", т.е. заполнение его данными, а почему я вижу в цикле push_back? второй поток не должен вызывать ни каких операций, связанных с изменением размеров вектора, этим должен заниматься первый поток,

соответственно, раз cx и cy напрямую зависят от scrlh, второй поток тоже не должен трогать эти переменные,
оставь и эту работу первому потоку

Цитата(wallstreet @  11.4.2012,  19:38 Найти цитируемый пост)
Предположим пользователь сидит и смотрит на пустое окно и размерность массива не выбирает, даже диалог1 не открывает. Так вот мне интересно, в этот момент мой таймер что делает, создает раз в секунду поток, который ожидает освобождения семафораХ? 

не создает, а пробуждает, или запускает,
на счет семафораХ уже сказал, на данный момент его должен заменить таймер

в принципе, задача так и стоит: по таймеру пускать всю цепочку событий, пользователю, конечно это может не так интересно наблюдать,

я бы мог предложить более интересный вариант:
заполнять массив не тупо значением j++, а добавить сюда элемент уникальности, например factor * j++,
тогда factor будет один раз инициализироваться перед заполнением массива, например так:
Код

factor = int( 10.0 * float( rand() ) / RAND_MAX );

тогда всякий раз, после запуска цепочки, картинка будет меняться,
пользователю будет не так скучно,

ну, или можно вообще отвязать изменение factor от потоков, а менять его значение в диалоге, вручную
Цитата(wallstreet @  11.4.2012,  19:38 Найти цитируемый пост)
Так вот вопросы эти появляются только потому, что после того как я определю размерность матрицы в диалоге1 программа отрисует один раз мой растр и все.

ну, это потому, что у тебя тут стоит TRUE:
Цитата

list[0] = hTimer;
list[1] = hSemaphoreX;
WaitForMultipleObjects(2,  list, TRUE, INFINITE);        // Ждем освобождения hSemaphoreX

а должно быть как минимум FALSE, ну а как оптимум: hSemaphoreX тут быть не должно,
хотя, если бы задача стояла: пускать первый поток либо по таймеру, либо по активности пользователя, то можно было бы и оставить,
это интересная практика, да и пользователю хорошо: изменения сразу вступают в силу, после закрытия диалога
Цитата(wallstreet @  11.4.2012,  19:38 Найти цитируемый пост)
почему заполняет только матрицу 10х10 правильно, а при заполнении 5х5, к примеру, то будет она выглядеть вот так:

а что не нравится?
тут все верно:
Код

_itot(*itV, str, vv.size());

это означает, что для 10x10 значения массива будут выведены в 10-чной системе счисления, для 5x5 - в 5-чной и т.д.
если надо все выводить в 10-чной, передавай в последний параметр 10, а не vv.size()


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
feodorv
Дата 12.4.2012, 18:03 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(GremlinProg @  12.4.2012,  08:34 Найти цитируемый пост)
таймер должен заменить семафорХ, а не дополнить,
просто удали семафорХ,

Здесь я не совсем согласен smile 
Изначально Event0 нужен был только для того, чтобы пробудить Thread1 не дожидаясь срабатывания таймера (то есть для корректного завершения программы).
В сущности, для этого же нужен SemaphoreX, ни больше ни меньше. То есть он нужен (если им правильно пользоваться):
Код

        WaitForMultipleObjects(2,  list, TRUE, INFINITE);        // Ждем освобождения hSemaphoreX

Конечно, так не годится. Ожидается и таймер и семафор одновременно. Зачем? Почему не так:
Код

WaitForMultipleObjects(2,  list, FALSE, INFINITE); 

Ээээ... Увидел
Цитата(GremlinProg @  12.4.2012,  08:34 Найти цитируемый пост)
а должно быть как минимум FALSE, ну а как оптимум: hSemaphoreX тут быть не должно,
хотя, если бы задача стояла: пускать первый поток либо по таймеру, либо по активности пользователя, то можно было бы и оставить,
это интересная практика, да и пользователю хорошо: изменения сразу вступают в силу, после закрытия диалога
 smile 


Цитата(GremlinProg @  12.4.2012,  08:34 Найти цитируемый пост)
соответственно, раз cx и cy напрямую зависят от scrlh, второй поток тоже не должен трогать эти переменные,
оставь и эту работу первому потоку

Опять же, не совсем согласен  smile 
cx и cy используются в отрисовке битмапа:
Код

BitBlt(hdc, 0, 0, cx, cy, hMemDC, 0, 0, SRCCOPY);               // Отрисовываем раст

Менять отдельно cx, cy и hMemSharedBitmap не стоит!!! Иначе говоря cx и cy нужно менять в Thread3 в момент
Код

hMemSharedBitmap = hMemBitmap;                                   // присваиваем значение hMemSharedBitmap нарисованного растра



То есть:
Код

unsigned int scrlhReal; // текущий размер 
unsigned int scrlhNew; // новый размер, который станет текущим в Thread1

unsigned _stdcall Thread1(void *param)
{
    while(!done)
    {
                ...
        WaitForMultipleObjects(2,  list, FALSE, INFINITE); 
        if(done) break;
        EnterCriticalSection(&csX);

        // Резайзим вектор
                scrlhReal = scrlhNew; // Сейчас вектор и его размер не соответствуют друг другу!!!
                ...resizeVector( scrlhReal );... // В этот момент вектор и его размер соответствуют друг другу
                // Но поскольку мы защищены критической секций, то всё в порядке))))

        LeaveCriticalSection(&csX);
        ReleaseSemaphore( hSemaphoreY, 1, NULL);
    }

    return 0;
}

unsigned _stdcall Thread2(void *param)
{
    while(!done)
    {
        WaitForSingleObject( hSemaphoreY, INFINITE);
        if(done) break;

        EnterCriticalSection(&csX);
        for( int column=0; column<scrlhReal; ++column)
        {
            for( int row=0; row<scrlhReal; ++row)
            {  
                           // Заполняем вектор
                           ...
            }
        }    
        LeaveCriticalSection(&csX);

        ReleaseSemaphore(hSemaphoreZ, 1, NULL);
    }
    return 0;
}

unsigned _stdcall Thread3(void *param)
{
    HDC hScreenDC, hMemDC;
    HGDIOBJ hMemBitmap;
    int dx, dy;

    while(!done)
    {
        WaitForSingleObject( hSemaphoreZ, INFINITE);
        if(done) break;

        hScreenDC = ::GetDC(HWND_DESKTOP);                         
        hMemDC = CreateCompatibleDC(hScreenDC);                    
        hMemBitmap = CreateCompatibleBitmap(hScreenDC, cx, cy);
        ::ReleaseDC(HWND_DESKTOP, hScreenDC);
        hMemBitmap = ::SelectObject( hMemDC, hMemBitmap);
        
        EnterCriticalSection(&csX);
        // Рисуем растр
        for( int count_row = 0, itVv=vv.begin(); itVv!=vv.end(); itVv++, count_row++)
        {
            for( int count_column = 0, itV=itVv->begin(); itV!=itVv->end(); itV++, count_column++)
            {
                _itot(*itV, str, 10);
                TextOut(hMemDC, count_column*30, count_row*30, str, _tcslen(str));
            }
        }

    dx = vv.size() * 30;
    dy = vv.size() * 30;
    LeaveCriticalSection(&csX);

    hMemBitmap = ::SelectObject( hMemDC, hMemBitmap); 
    ::DeleteDC(hMemDC); 

    EnterCriticalSection(&csShared);
        if( hMemSharedBitmap != NULL ) DeleteObject( hMemSharedBitmap );
        hMemSharedBitmap = hMemBitmap; 
    cx = dx;
    cy = dy;
    LeaveCriticalSection(&csShared);

        InvalidateRect((HWND)param, FALSE, TRUE);
    }

    return 0;
}



Тут же встают проблемы инициализации и очистки  smile 

Код

        hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
        SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE);
        hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, hWnd, 0, NULL);
        hThread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, hWnd, 0, NULL);
        hThread3 = (HANDLE)_beginthreadex(NULL, 0, Thread3, hWnd, 0, NULL);

Цитата(wallstreet @  11.4.2012,  18:38 Найти цитируемый пост)
Он у меня создается в момент создания окна. Создается без задержек и сразу же запускает потоки, но потоки не отрисовывают раст, т.к. семафорХ не запущен. Этот семафор освободит диалог1 после того как пользователь определится с размерностью матрицы, которую хочет видеть на экране и нажмет кнопку "ОК". 

Если хочется всё стартовать через Dialog1, то можно сделать так:
Код

BOOL inited = FALSE; // глобальная переменная

BOOL launchDialog( HWND owner )
{
  if( DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), owner, Dialog1) == IDOK )
  {
    if( !inited )
    {
    hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
    SetWaitableTimer(hTimer, &lTime, 1000, NULL, NULL, FALSE);
    hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, hWnd, 0, NULL);
    hThread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, hWnd, 0, NULL);
    hThread3 = (HANDLE)_beginthreadex(NULL, 0, Thread3, hWnd, 0, NULL);
        inited = TRUE;
    }
    return TRUE;
  }
  return FALSE;
}


Соответственно в Dialog1:
Код

...
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDOK:
            scrlhNew = scrlh;
            j = 0;
        
        case IDCANCEL:
            return EndDialog(hDlg, LOWORD(wParam)); // <-----------!!!!
        }
        return TRUE;
...


Соответственно в WndProc убрать код инициализации hTimer, ThreadXXX и 
Код

...
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_FILE_SETTINGS:
            launchDialog( hWnd );
            break;
...


Можно launchDialog вызвать и в момент окончания инициализации главного окна (принудить пользователя к действиям), но это особая история...


Код

        case IDM_EXIT:
            done = TRUE;
            // чистим вектор
            vv.clear();
            HANDLE list[3];
            list[0] = hThread1;
            list[1] = hThread2;
            list[2] = hThread3;
            WaitForMultipleObjects(3, list, TRUE, 10000); // Ждем завершения всех потоков
                        ...

Во-первых, vv.clear() стоит делать только после завершения всех потоков. Во-вторых, потоки нужно предварительно пробудить. В-третьих
Код

            DeleteDC(hMemDC);

это лишнее, а вот hMemSharedBitmap освободить нужно!!! В четвёртых, надо освободить таймер. В пятых, перед ожидаем потоков, стоит проверить, что они вообще были запущены. То же к таймеру и семафорам.


Цитата(wallstreet @  9.4.2012,  23:09 Найти цитируемый пост)
Ну так еще бы, проект сырой очень, да и вообще)

Да я не в притензии, я для дела сугубо)))


Цитата(GremlinProg @  12.4.2012,  08:34 Найти цитируемый пост)
это означает, что для 10x10 значения массива будут выведены в 10-чной системе счисления, для 5x5 - в 5-чной и т.д.
если надо все выводить в 10-чной, передавай в последний параметр 10, а не vv.size()

 smile 

Это сообщение отредактировал(а) feodorv - 12.4.2012, 18:18


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
GremlinProg
Дата 13.4.2012, 07:46 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  12.4.2012,  20:03 Найти цитируемый пост)
Изначально Event0 нужен был только для того, чтобы пробудить Thread1 не дожидаясь срабатывания таймера (то есть для корректного завершения программы).В сущности, для этого же нужен SemaphoreX, ни больше ни меньше. То есть он нужен (если им правильно пользоваться):

Event0 - это семафорХ?
если так, то изначально этот семафор пускал первый поток,
о завершении потоков мы как-то уже договорились, что пока на нем заморачиваться не будем,

потом, для завершения всех потоков лучше сделать одно событие hAbort, которое и заменит флаг done
Цитата(feodorv @  12.4.2012,  20:03 Найти цитируемый пост)

cx и cy используются в отрисовке битмапа:
Код

BitBlt(hdc, 0, 0, cx, cy, hMemDC, 0, 0, SRCCOPY);               // Отрисовываем раст

Менять отдельно cx, cy и hMemSharedBitmap не стоит!!!

если не опираться на cx и cy в 3-м потоке, при создании растра, то да, так будет безопасно для основного потока,
хотя он может получить эту же информацию из растра, через GetObject,

на счет безопасности в основном потоке я бы как раз пока особо не переживал,
я сейчас говорю об инициализации растра в 3-м потоке,

теоретически, раз от размера вектора зависит размер растра,
и размер вектора выставляется в критической секции x,
то разумно было бы и размер растра выставлять/получать в этом критическом участе кода,
тогда нет разницы, в каком потоке это будет сделано


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 13.4.2012, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Всем спасибо за помощь.
кое что подправил, завтра думаю добью если время будет.


Ссылка на проект =>проект
PM MAIL   Вверх
feodorv
Дата 13.4.2012, 21:36 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



GremlinProg
Цитата(GremlinProg @  13.4.2012,  08:46 Найти цитируемый пост)
на счет безопасности в основном потоке я бы как раз пока особо не переживал,

Конечно, при отрисовке битмапа неверные cx и cy не скажутся на безопасности выполнения основного потока, но дело в принципе:
Код

unsigned _stdcall Thread1(void *param)
{
    while(!done)
    {
        HANDLE list[2];
        list[0] = hTimer;
        list[1] = hSemaphoreX;
        WaitForMultipleObjects(2, list, FALSE, INFINITE);        // Ждем освобождения hTimer или семафора
        if(done)
            break;
        EnterCriticalSection(&csX);                              // защита модификации и чтения вектора
        if(vv.size())
        {
            vv.resize(::scrlh);                                  // вот тут я не знаю правильно я это делаю или нет!!!!!
            vv.erase(vv.begin(), vv.end());                      // при уменьшении размера вектора отрисовка растра подтормаживает!!!!        
        }
        vv.reserve(::scrlh);                                     // задаем размер вектора если он нулевой

        ::cx = ::scrlh * 30;                                     // сразу же задаем размер переменных для битмапа
        ::cy = ::scrlh * 30;
        LeaveCriticalSection(&csX);
        ReleaseSemaphore(hSemaphoreY, 1, NULL);                  // Освобождаем hSemaphoreY для третьего потока
    }

    return 0;
}

Между Thread1 и Thread3 может случится WM_PAINT. При этом hMemSharedBitmap ещё старая, а значения cx и cy уже новые, не когерентные с hMemSharedBitmap...


Цитата(GremlinProg @  13.4.2012,  08:46 Найти цитируемый пост)
хотя он может получить эту же информацию из растра, через GetObject,

Вот это было бы лучше всего (чтобы не было путаницы), а от cx и cy можно будет отказаться вообще...


Цитата(GremlinProg @  13.4.2012,  08:46 Найти цитируемый пост)
теоретически, раз от размера вектора зависит размер растра,
и размер вектора выставляется в критической секции x,
то разумно было бы и размер растра выставлять/получать в этом критическом участе кода,
тогда нет разницы, в каком потоке это будет сделано 

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


wallstreet
Код

            vv.erase(vv.begin(), vv.end());                      // при уменьшении размера вектора отрисовка растра подтормаживает!!!!    

В смысле???


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
GremlinProg
Дата 14.4.2012, 16:26 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(feodorv @  13.4.2012,  23:36 Найти цитируемый пост)
Между Thread1 и Thread3 может случится WM_PAINT

равно как и между Thread3 и WM_PAINT может случиться Thread1 и Thread2 smile
Цитата(feodorv @  13.4.2012,  23:36 Найти цитируемый пост)
vv.reserve(::scrlh);                                     // задаем размер вектора если он нулевой

reserve не задает размер вектора, здесь нужен resize
Цитата(feodorv @  13.4.2012,  23:36 Найти цитируемый пост)
Вот это было бы лучше всего (чтобы не было путаницы), а от cx и cy можно будет отказаться вообще...

 smile 
либо отказаться, либо завести еще пару, ибо под одним синхронизатором кто-нибудь обязательно будет в пролете: либо растр, либо WM_PAINT
Цитата(feodorv @  13.4.2012,  23:36 Найти цитируемый пост)
Прошу прощения, но эта мысль никак не желает достигнуть нужных отделов моего слабеющего мозга)))

судя по коду, она все же нашла, что искала  smile 


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 17.4.2012, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Цитата

Вот это было бы лучше всего (чтобы не было путаницы), а от cx и cy можно будет отказаться вообще...

Ну, полностью отказаться я не знаю как, т.к. при создании растра hMemBitmap, в третьем потоке, мы задаем его размеры.
Код

hMemBitmap = CreateCompatibleBitmap(hScreenDC, cx, cy); 

В этот момент еще нет хендла растра из которого можем вытащить высоту и ширину. 
Т.о. я оставил инициализацию cx и cy в первом потоке исключительно для создания первого растра hMemBitmap. В то время как для отрисовки в WM_PAINT я ширину и высоту вытаскиваю из уже готового растра hMemSharedBitmap, которому до этого присваиваю hMemBitmap.
Если вы покажете способ избавиться от сх и су полностью, буду признателен.

Код

vv.resize(::scrlh);                                      // вот тут я не знаю правильно я это делаю или нет!!!!!
vv.erase(vv.begin(), vv.end());                          // при уменьшении размера вектора отрисовка растра подтормаживает!!!    

Цитата

В смысле???

Видимо я неполноценно выразил свою мысль, но если вы попробуете размер матрицы установить, предположим, в 10х10 с помощью скроллбара, а затем второй раз, уже рисующийся растр изменить на размер 5х5 с помощью все того же скроллбара, то заметите как он где-то на секунду приостановит отрисовку и потом уже нарисует правильный размер матрицы, а при увеличении размера, такой задержки не последует. Так вот меня интересовали причины по которым отрисовка подтормаживается при уменьшении размера растра. Собственно на выше приведенный участок кода я и стал грешить, хотя может зря, может причина в другом?


ссылка на проект:скачать проект
PM MAIL   Вверх
GremlinProg
Дата 18.4.2012, 06:40 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  17.4.2012,  18:53 Найти цитируемый пост)
Ну, полностью отказаться я не знаю как, т.к. при создании растра hMemBitmap, в третьем потоке, мы задаем его размеры.

Код

BITMAP Bm;
::GetObject( hSharedBitmap, sizeof( Bm ), &Bm );
Bm.bmWidth; // это cx
Bm.bmHeight; // это cy

Цитата(wallstreet @  17.4.2012,  18:53 Найти цитируемый пост)
vv.erase(vv.begin(), vv.end());

это равнозначно такому коду:
Код

vv.clear();

т.е. таким кодом ты дважды меняешь размер вектора, причем в конечном счете он оказывается пустым

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


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
GremlinProg
Дата 18.4.2012, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(GremlinProg @ 18.4.2012,  08:40)
Цитата(wallstreet @  17.4.2012,  18:53 Найти цитируемый пост)
Ну, полностью отказаться я не знаю как, т.к. при создании растра hMemBitmap, в третьем потоке, мы задаем его размеры.

Код

BITMAP Bm;
::GetObject( hSharedBitmap, sizeof( Bm ), &Bm );
Bm.bmWidth; // это cx
Bm.bmHeight; // это cy


упс, недопонял  smile 
я этот код привел для WM_PAINT'а, т.е. не для 3-го, а для основного потока


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 18.4.2012, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Код

BITMAP Bm;
::GetObject( hSharedBitmap, sizeof( Bm ), &Bm );
Bm.bmWidth; // это cx
Bm.bmHeight; // это cy

да да да, именно так я и вытаскиваю высоту и ширину из hSharedBitmap в WM_PAINT, но не использовать сx и cy в третьем потоке не знаю как. Хотя по большому счету если не запустится поток2, то не запустится и поток3, а второй запускается только после того как зпускается поток1 в котором инициализируются сx и су. Так что между потоками нестыковок в работе не должно быть, а в WndProc при отрисовке берется высота и ширина из битмапа, так что думаю все ок тут с синхронизацией.
Цитата

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

Я понимаю так. Поток1 ресайзит вектор. Предположим, что он уже заполнен значениями 1, 2, 3, 4, 5. 
Так вот если я изменяю его размер вот так:
Код

vv.resize(8);

то получу в результате: 1, 2, 3, 4, 5, NULL, NULL, NULL и если я в дальнейшем не удалю значения оставив только размерность, то используя push_back() во втором потоке, значения вставятся непонятно как для меня. Т.е. если убрать удаление элементов вектора из потока1, то WM_PAINT отрисовывает черный квадрат заданой размерности, без чисел.
Изначально думал резервировать  память под вектор, если его размер 0, в потоке1 функцией reserve(), а в потоке2 заполнять исходя из его capacity() простым циклом. Если же вектор.size() > 0 тогда изменять его размер функцией resize(), но как проблему решить с очисткой от значений я не знал поэтому все на выходе получалось через стерни к звездам.

Добавлено через 14 минут и 11 секунд
вообще думал сделать изменение размера вектора и его заполнение как-то так:
Поток1
Код

if(!vv.size())                                           // если в векторе нет ни одного элемента, то
        {
            vv.reserve(::scrlh);                                 // устанавливаем вместимость вектора
        }
        else                                                     // если размер вектора больше 0
        {
            vv.resize(::scrlh);                                  // изменяем размер на актуальный
        }

Поток2
Код

// ЗАПОЛНЕНИЕ ВЕКТОРА
        if(!vv.size())                                           // если элементов нет (может произойти если мы изменили вместимость, 
                                                                 // но не заполнили) то
        {
            for(int column=0; column<vv.capacity(); ++column)    // заполняем матрицу случайными значениями, при этом сотрируем до 
                                                                 // максимально возможного размера вектора до того как ему потребуется 
                                                                 // выделить больше места column<vv.capacity()
            {                                                    
                for(int row=0; row<vv.capacity(); ++row)
                {  
                    ::j = rand()%100;
                    v.push_back(j++);
                }

                vv.push_back(v);
                v.clear();
            }
        }
        else
        {
            vv.assign(vv.begin(), vv.end());                     // Здесь мы перезаписываем наш вектор в этот же вектор, но с заменой значений
            for(int column=0; column<vv.size(); ++column)        // Тут испльзуем уже реальный размер вектора а не зарезервированый column<vv.size()
            {                                                    
                for(int row=0; row<vv.size(); ++row)
                {  
                    ::j = rand()%100;
                    v.push_back(j++);
                }

                vv.push_back(v);
                v.clear();
            }
        }

Но этот код не работает, матрица отрисовывается один раз и вылазит ошибка Debug Assertion Failed!
Expression: vector iterators incompatible
PM MAIL   Вверх
GremlinProg
Дата 18.4.2012, 12:51 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @ 18.4.2012,  14:30)

Цитата

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

Я понимаю так. Поток1 ресайзит вектор. Предположим, что он уже заполнен значениями 1, 2, 3, 4, 5. 
Так вот если я изменяю его размер вот так:
Код

vv.resize(8);

то получу в результате: 1, 2, 3, 4, 5, NULL, NULL, NULL и если я в дальнейшем не удалю значения оставив только размерность, то используя push_back() во втором потоке, значения вставятся непонятно как для меня. Т.е. если убрать удаление элементов вектора из потока1, то WM_PAINT отрисовывает черный квадрат заданой размерности, без чисел.
Изначально думал резервировать  память под вектор, если его размер 0, в потоке1 функцией reserve(), а в потоке2 заполнять исходя из его capacity() простым циклом. Если же вектор.size() > 0 тогда изменять его размер функцией resize(), но как проблему решить с очисткой от значений я не знал поэтому все на выходе получалось через стерни к звездам.

ну смотри, в первом потоке задаешь размер массива:
Код

vv.resize( new_size );
for( auto It = vv.begin() ; It != vv.end() ; ( It++ )->resize( new_size ) );

а во втором его заполняешь:
Код

for( auto It = vv.begin() ; It != vv.end() ; ++It ){
  for( auto Jt = It->begin() ; Jt != It->end() ; ++Jt ){
    *Jt = j++;
  }
}

если проблем с синхронизацией нет, значит ошибок тут тоже не будет, и не важно, какой размер был на предыдущей итерации,
черный квадрат у тебя точно не из-за того, что сохраняются старые значения в массиве


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 18.4.2012, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Цитата(GremlinProg @  18.4.2012,  12:51 Найти цитируемый пост)
for( auto It = vv.begin() ; It != vv.end() ; ( It++ )->resize( new_size ) );

эээ.. стесняюсь спросить auto это что?
насколько я понимаю it это итератор, но чем он отличается от std::vector<std::vector<int>>::iterator it?

Это сообщение отредактировал(а) wallstreet - 18.4.2012, 13:53
PM MAIL   Вверх
GremlinProg
Дата 18.4.2012, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(wallstreet @  18.4.2012,  15:52 Найти цитируемый пост)
но чем он отличается от std::vector<std::vector<int>>::iterator it

ни чем не отличается


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 18.4.2012, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Последовал вашим советам и вроде все заработало, но зависание при уменьшении матрицы осталось все равно.
Честно признаться работало и раньше все так же, когда вместо предложенного вами варианта я использовал в потоке1 просто 
Код

vv.resize(::scrlh);

Возможно я просто еще догнать не могу сути мысли, но до подобных синтаксических конструкций типо:
Код

(it++)->resize(::scrlh)

я самостоятельно бы не дошел, во всяком случае сейчас, и меня это ужасно расстраивает. smile 



Ссылка на проект

Это сообщение отредактировал(а) wallstreet - 18.4.2012, 15:19
PM MAIL   Вверх
GremlinProg
Дата 18.4.2012, 17:01 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



это всего лишь С++,
то же самое можно было записать проще:
Код

vv.resize( new_size );
for( auto It = vv.begin() ; It != vv.end() ; ++It ){
  It->resize( new_size );
}

и это было бы правильно

p.s.:на счет зависания, пока не смотрел, пока нет возможности


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 18.4.2012, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Я вот тут подумал, таймер запускает потоки и отрисовывает раст с задаными параметрами, в часности с размером ::scrlh, который я беру из глобальной переменной в первом потоке и инициализирую сх и су, а в этот момент уже поменял глобальную переменную через диалог1. 
И создается такая ситуация, что я меняю глобальную ::scrlh нажимая "ОК", именно в тот момент когда отрисовывается в WM_PAINT раст со старым значением ::scrlh, которая защищена критической секцией csShared. Так вот если защитить в диалоге1 изменение глобальной ::scrlh с помощью секции csShared, что бы инициализация глобальной ::scrlh проходила между тактами отрисовки по таймеру?
Я спрашиваю, потому, что на домашнем компьютере это подтормаживание не видно почему-то)))
PM MAIL   Вверх
GremlinProg
Дата 19.4.2012, 07:28 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



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

for(auto it=vv.begin(); it!=vv.end(); (it++)->resize(::scrlh));

в конечном счете, получится искажение массива

в потоке scrlh читается под секцией csX, если в диалоге так же менять ее под секцией csX, то все будет хорошо
2. GetObject в 3-м потоке совершенно не нужна, она нужна в WM_PAINT, под секцией csShared,

ничего стршного тут конечно нет, т.к. GetObject защищен той же csShared,
просто зачем тратить время 3-го потока на работу основного (WM_PAINT)

пока больше ничего военного не заметил

Добавлено @ 07:34
Цитата(wallstreet @  18.4.2012,  22:45 Найти цитируемый пост)
И создается такая ситуация, что я меняю глобальную ::scrlh нажимая "ОК", именно в тот момент когда отрисовывается в WM_PAINT раст со старым значением ::scrlh, которая защищена критической секцией csShared. Так вот если защитить в диалоге1 изменение глобальной ::scrlh с помощью секции csShared, что бы инициализация глобальной ::scrlh проходила между тактами отрисовки по таймеру?

это я еще не очень понял, т.е. ты думаешь, что если изменения scrlh защитить csShared, то отрисовка массива будет синхронизирована с этим изменением?

если так, то нет,
это просто приведет к тому, что ты не сделаешь эти 2 операции одновременно ( WM_PAINT и scrlh ), hSemaphoreX у тебя и так актуализирует изменения пользователя на сколько это только возможно, т.к. после
Код

ReleaseSemaphore(hSemaphoreX, 1, NULL);

первый поток, если не загружен, сразу начинает работу с новыми параметрами

Это сообщение отредактировал(а) GremlinProg - 19.4.2012, 07:35


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
wallstreet
Дата 19.4.2012, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



Цитата(GremlinProg @  19.4.2012,  07:28 Найти цитируемый пост)
в потоке scrlh читается под секцией csX, если в диалоге так же менять ее под секцией csX, то все будет хорошо2. GetObject в 3-м потоке совершенно не нужна, она нужна в WM_PAINT, под секцией csShared,

Исправил. Вроде больше вопросов нет.
Всем спасибо)
PM MAIL   Вверх
feodorv
Дата 19.4.2012, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(wallstreet @  19.4.2012,  10:55 Найти цитируемый пост)
Исправил. Вроде больше вопросов нет.
Всем спасибо) 

То есть всё? На этом завершаем?)))
Тогда, как любит говорить bsa, пометь тему решённой)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
wallstreet
Дата 26.4.2012, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 11.8.2011

Репутация: нет
Всего: нет



ок
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.1513 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.