我正在尝试使用 WinXP SP3 上的 Borland 的 C++ Builder 6 编写多线程图形处理程序,但遇到了(我认为)同步问题,并且无法弄清楚原因。
主窗体 (Form1) 具有从文件加载的 TPicture。线程通过 Sync() 调用获取此副本,并且工作正常。线程对图像执行一些工作,理论上,它会定期更新主窗体图像。主表单还控制机器,并且是"第一手段"紧急停止,因此无法选择阻塞。一切都很好,直到主窗体获得工作副本或工作副本的副本(对不起,但它必须这样做),此时程序挂起,并且仅响应来自 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);
}
最后一次尝试有效,尽管相对较慢,因为剪贴板开销,它充其量是一个糟糕的拐杖。我怀疑剪贴板正在强制执行否则失败的同步工作,但是,正如我之前所说,我无法理解为什么。可能是什么问题?
谢谢你的评论,雷米。他们把我从试图解决问题时陷入的"晕眩"中惊醒。我忘记了Windows需要移动内存块,如果锁定它们,则无法执行此操作。
同步(更新)调用(上面的代码块 1)的初始问题是由于我在调用期间仍然锁定了工作副本 (Imgcopy)(从线程内部),阻止了主窗体随后访问它。我怀疑(但尚未调查 - 代码已经消失)相同的根本原因在代码块 2 中起作用。
在访问之前锁定每个位图,并在访问后立即解锁解决了这个问题。
Peter O,感谢您的编辑 - 我没有意识到我最初的帖子中有这么多开销。