Многопоточность Синхронизация

Я пытаюсь написать многопоточную программу для работы с графикой, используя Borland C++ Builder 6 для WinXP SP3, но столкнулся (я думаю) с проблемой синхронизации и не могу понять, почему.

Основная форма (Form1) имеет TPicture, загруженный из файла. Копия этого получается потоком через вызов Synchronize(), и работает нормально. Поток выполняет некоторую работу с изображением и теоретически периодически обновляет основное изображение формы. Основная форма также управляет машиной и является аварийной остановкой "First Resort", поэтому блокировка не возможна. Все в порядке, пока основная форма не заполучит рабочую копию или копию рабочей копии (извините, но она дошла до этого), после чего программа зависает и реагирует только на "сброс программы" из IDE., Плохое решение - скопировать рабочее изображение в буфер обмена, а затем скопировать его из основной формы в основное изображение формы.

        //Synchronization routines:
//----------------------------------------------------------------
`void __fastcall ImageRout::update()
{
Form1->Image9->Picture->Bitmap->Assign(Imgcopy);
//never returns
}
//----------------------------------------------------------------
void __fastcall ImageRout::getimage()
{
    Imgcopy->Assign(Form1->Image9->Picture);
}
//----------------------------------------------------------------

//do the initialisation things... Then,
//(data is a struct, loaded with image data via a Synchronize() call)
Imgcopy=new Graphics::TBitmap;
Imgcopy->Width=data.width;
Imgcopy->Height=data.height;    //size the bitmap
while(Imgcopy->Canvas->LockCount!=1)
{
    Imgcopy->Canvas->TryLock();
}  //have to Lock() the image or it gets lost... Somewhere
Synchronize(getimage);  //works fine

//do some work on Imgcopy

//"By the book"- attempt 1
//(rate (=15) is a 'brake' to stop every alteration being displayed)
update_count++;
if(update_count>rate)   //after a few iterations, update
{           //user interface
     Synchronize(update);  //fails: never returns from Synchronize call
     update_count=0;
}           

После многих неудачных попыток я придумал это.

//in the thread...

update_count++;
if(update_count>rate)
{
     EnterCriticalSection(&Form1->mylock1);
     Form1->tempimage->Assign(Imgcopy);        //tempimage is another bitmap, 
     InterlockedExchange(&Form1->imageready,1);//declared in the main Form
     LeaveCriticalSection(&Form1->mylock1);    //and is only ever accessed
     update_count=0;                           //inside a critical section
}

//...and in the main Form....

if(imageready==1)
{
     EnterCriticalSection(&mylock1);
     Image9->Picture->Bitmap->Assign(tempimage);     //Fails here
     InterlockedExchange(&gotimage,1);
     InterlockedExchange(&imageready,0);
     LeaveCriticalSection(&mylock1);
}

Итак, в отчаянии.

//in the thread...
update_count++;
if(update_count>rate)
{
     Synchronize(update);
     EnterCriticalSection(&Form1->mylock1);
     Form1->tempimage->Assign(Imgcopy);
     Clipboard()->Assign(Imgcopy);
     InterlockedExchange(&Form1->imageready,1);
     LeaveCriticalSection(&Form1->mylock1);  */
     update_count=0;
}

//and in the main Form...
if(imageready==1)
{
     EnterCriticalSection(&mylock1);
     if (Clipboard()->HasFormat(CF_BITMAP))
     {
          Image9->Picture->Bitmap->Assign(Clipboard());
     }
     InterlockedExchange(&gotimage,1);
     InterlockedExchange(&imageready,0);
     LeaveCriticalSection(&mylock1);
}

Эта последняя попытка работает, хотя и относительно медленно, из-за накладных расходов буфера обмена, и в лучшем случае это плохой костыль. Я подозреваю, что буфер обмена вызывает иные неудачные попытки синхронизации, но, как я уже говорил, я не могу понять, почему. В чем может быть проблема?

1 ответ

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

Первоначальная проблема вызова Synchronize(update) (кодовый блок 1 выше) была вызвана тем, что во время вызова у меня все еще была заблокирована рабочая копия (Imgcopy) (изнутри потока), что не позволяло основной форме впоследствии получить к ней доступ. Я подозреваю (но не исследовал - этот код исчез) та же самая основная причина была в работе в блоке кода 2.

Блокировка каждого растрового изображения непосредственно перед доступом и немедленная разблокировка решили эту проблему.

Питер О, спасибо за ваше редактирование - я не осознавал, что в моем первом посте было так много служебной информации.

Другие вопросы по тегам