Многопоточность Синхронизация
Я пытаюсь написать многопоточную программу для работы с графикой, используя 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.
Блокировка каждого растрового изображения непосредственно перед доступом и немедленная разблокировка решили эту проблему.
Питер О, спасибо за ваше редактирование - я не осознавал, что в моем первом посте было так много служебной информации.