void __fastcall TCvsConnection::TRealCamDataProvider::Execute()
{
for(; !Terminated; )
{
pCvsConnection->pLockStructures->Acquire();
try {
GetData();
DeliverData();
}
__finally
{
pCvsConnection->pLockStructures->Release();
};
Sleep(msec >> 1);
};
}
Неожиданая остановка потока (Finished == true)
Есть поток:
Код:
, и некоторая функция, которая шарит данные с потоком.
При входе в критическую секцию поток останавливается (Finished == true):
Код:
void __fastcall TCvsConnection::UnRegisterCvsCameraComponent(TCvsCamera *CvsCamera)
{
// pRealCamDataProvider->Finished == false
pLockStructures->Acquire();
// pRealCamDataProvider->Finished == true
try {
if(CvsCamera)
{
if(CvsCamera->CvsConnection)
CvsCamera->CvsConnection = NULL;
int i;
if((i = pRealCamDataProvider->pCvsCameraComponents->IndexOf(CvsCamera)) != -1)
{
if(--FCamRefCount == 0)
{
pRealCamDataProvider->Terminate();
pRealCamDataProvider->WaitFor();
};
pRealCamDataProvider->pCvsCameraComponents->Delete(i);
pRealCamDataProvider->DeleteServerCamera(
CvsCamera->Cam - FirstCam
);
if(FCamRefCount == 0)
{
delete pRealCamDataProvider;
pRealCamDataProvider = NULL;
};
};
};
}
__finally {
pLockStructures->Release();
};
}
{
// pRealCamDataProvider->Finished == false
pLockStructures->Acquire();
// pRealCamDataProvider->Finished == true
try {
if(CvsCamera)
{
if(CvsCamera->CvsConnection)
CvsCamera->CvsConnection = NULL;
int i;
if((i = pRealCamDataProvider->pCvsCameraComponents->IndexOf(CvsCamera)) != -1)
{
if(--FCamRefCount == 0)
{
pRealCamDataProvider->Terminate();
pRealCamDataProvider->WaitFor();
};
pRealCamDataProvider->pCvsCameraComponents->Delete(i);
pRealCamDataProvider->DeleteServerCamera(
CvsCamera->Cam - FirstCam
);
if(FCamRefCount == 0)
{
delete pRealCamDataProvider;
pRealCamDataProvider = NULL;
};
};
};
}
__finally {
pLockStructures->Release();
};
}
Такое происходит через раз (случайно). При этом ни pRealCamDataProvider->Terminate(); , ни delete pRealCamDataProvider; , в приведенной функции нигде не вызываются.
В чем причина?
Код:
procedure TEventWaitThread.Execute;
begin
while True do
begin
if WaitForSingleObject(CommandEvent, INFINITE) <> WAIT_OBJECT_0 then Exit;
PostMessage(face.Handle, WM_CommandArrived, 0, 0);
end;
end;
begin
while True do
begin
if WaitForSingleObject(CommandEvent, INFINITE) <> WAIT_OBJECT_0 then Exit;
PostMessage(face.Handle, WM_CommandArrived, 0, 0);
end;
end;
По неизвестной причине код стал самостоятельно завершатся без причинно.
если закоментировать строчку '((TCvsCamera*)(lste->GetCurrent()))->PaintFrame();',
то все работает.
Код:
void __fastcall TCvsConnection::TRealCamDataProvider::DeliverData()
{
TListEnumerator *lste = pCvsCameraComponents->GetEnumerator();
while(lste->MoveNext())
{
((TCvsCamera*)(lste->GetCurrent()))->PaintFrame();
};
}
{
TListEnumerator *lste = pCvsCameraComponents->GetEnumerator();
while(lste->MoveNext())
{
((TCvsCamera*)(lste->GetCurrent()))->PaintFrame();
};
}
Код:
void __fastcall TCvsCamera::PaintFrame()
{
if(FCvsConnection && FActive && Parent)
{
int icam = FCam - FCvsConnection->FirstCam;
byte *pJpeg = FCvsConnection->pRealCamDataProvider->pFrames[icam];
#pragma warn -8098
if(pJpeg && (*(DWORD*)(pJpeg+6) != 'FIFJ'))
pJpeg = FCvsConnection->GetPicNoSignal();
#pragma warn .8098
int w, h, channels;
GetJpegWH(pJpeg, &w, &h, &channels);
char *buf = new char[w * h * channels];
DecompFromJPEGBuf(
pJpeg,
w * h * channels,
w,
h,
channels,
buf
);
Canvas->Lock();
HDC hdcDst = Canvas->Handle;
HDC hdcSrc = CreateCompatibleDC(hdcDst);
HBITMAP hbmSrc = CreateCompatibleBitmap(hdcDst,
Width,
Height
);
SelectObject(hdcSrc, hbmSrc);
HDC hdcTitle = CreateCompatibleDC(hdcDst);
HBITMAP hbmTitle = CreateCompatibleBitmap(hdcDst,
Width,
24
);
TCanvas *cnvSrc = new TCanvas();
cnvSrc->Handle = hdcSrc;
//
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = w;
// это баг микрософта, высота должна быть отрицательной
bi.bmiHeader.biHeight = -h;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 8 * channels;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = w * h * channels;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
// масштабируем Jpeg на hdcSrc:
cnvSrc->Lock();
SetStretchBltMode(hdcSrc, HALFTONE);
StretchDIBits(
hdcSrc,
0,
0,
Width,
Height,
0,
0,
w,
h,
buf,
&bi,
DIB_RGB_COLORS,
SRCCOPY
);
delete buf;
// рисуем верхний прямоугольник для статусной строки:
SelectObject(hdcTitle, hbmTitle);
TCanvas *cnvTitle = new TCanvas();
cnvTitle->Handle = hdcTitle;
cnvTitle->Lock();
cnvTitle->Brush->Color = clBlack;
cnvTitle->Rectangle(0, 0, Width, 24);
BLENDFUNCTION blend = {AC_SRC_OVER, 0, 128, 0};
// и накладываем его на hdcSrc с использованием альфа-канала:
::AlphaBlend(
hdcSrc,
0,
0,
Width,
24,
hdcTitle,
0,
0,
Width,
24,
blend
);
cnvTitle->Font->Color = clWhite;
cnvTitle->Font->Size = 14;
cnvTitle->TextRect(TRect(96, 0, Width + 96, 24), 96, 0, Title);
if(CvsConnection->CamStatusData[Cam - FCvsConnection->FirstCam].InfoAlarm)
{
cnvTitle->Brush->Style = bsSolid;
cnvTitle->Brush->Color = clRed;
cnvTitle->Pen->Color = clRed;
cnvTitle->Ellipse(2, 2, 20, 20);
}
if(CvsConnection->CamStatusData[Cam - FCvsConnection->FirstCam].InfoActive)
{
cnvTitle->Brush->Style = bsSolid;
cnvTitle->Brush->Color = clLime;
cnvTitle->Pen->Color = clLime;
cnvTitle->Ellipse(24, 2, 44, 20);
};
// добавляем на hdcSrc информацию о статусе:
::TransparentBlt(
hdcSrc,
0,
0,
Width,
24,
hdcTitle,
0,
0,
Width,
24,
clBlack
);
cnvTitle->Unlock();
delete cnvTitle;
DeleteObject(hbmTitle);
DeleteDC(hdcTitle);
// отображаем результат на hdcDst:
BitBlt(
hdcDst,
0,
0,
Width,
Height,
hdcSrc,
0,
0,
SRCCOPY
);
cnvSrc->Unlock();
Canvas->Unlock();
delete cnvSrc;
DeleteObject(hbmSrc);
DeleteDC(hdcSrc);
};
}
{
if(FCvsConnection && FActive && Parent)
{
int icam = FCam - FCvsConnection->FirstCam;
byte *pJpeg = FCvsConnection->pRealCamDataProvider->pFrames[icam];
#pragma warn -8098
if(pJpeg && (*(DWORD*)(pJpeg+6) != 'FIFJ'))
pJpeg = FCvsConnection->GetPicNoSignal();
#pragma warn .8098
int w, h, channels;
GetJpegWH(pJpeg, &w, &h, &channels);
char *buf = new char[w * h * channels];
DecompFromJPEGBuf(
pJpeg,
w * h * channels,
w,
h,
channels,
buf
);
Canvas->Lock();
HDC hdcDst = Canvas->Handle;
HDC hdcSrc = CreateCompatibleDC(hdcDst);
HBITMAP hbmSrc = CreateCompatibleBitmap(hdcDst,
Width,
Height
);
SelectObject(hdcSrc, hbmSrc);
HDC hdcTitle = CreateCompatibleDC(hdcDst);
HBITMAP hbmTitle = CreateCompatibleBitmap(hdcDst,
Width,
24
);
TCanvas *cnvSrc = new TCanvas();
cnvSrc->Handle = hdcSrc;
//
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = w;
// это баг микрософта, высота должна быть отрицательной
bi.bmiHeader.biHeight = -h;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 8 * channels;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = w * h * channels;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
// масштабируем Jpeg на hdcSrc:
cnvSrc->Lock();
SetStretchBltMode(hdcSrc, HALFTONE);
StretchDIBits(
hdcSrc,
0,
0,
Width,
Height,
0,
0,
w,
h,
buf,
&bi,
DIB_RGB_COLORS,
SRCCOPY
);
delete buf;
// рисуем верхний прямоугольник для статусной строки:
SelectObject(hdcTitle, hbmTitle);
TCanvas *cnvTitle = new TCanvas();
cnvTitle->Handle = hdcTitle;
cnvTitle->Lock();
cnvTitle->Brush->Color = clBlack;
cnvTitle->Rectangle(0, 0, Width, 24);
BLENDFUNCTION blend = {AC_SRC_OVER, 0, 128, 0};
// и накладываем его на hdcSrc с использованием альфа-канала:
::AlphaBlend(
hdcSrc,
0,
0,
Width,
24,
hdcTitle,
0,
0,
Width,
24,
blend
);
cnvTitle->Font->Color = clWhite;
cnvTitle->Font->Size = 14;
cnvTitle->TextRect(TRect(96, 0, Width + 96, 24), 96, 0, Title);
if(CvsConnection->CamStatusData[Cam - FCvsConnection->FirstCam].InfoAlarm)
{
cnvTitle->Brush->Style = bsSolid;
cnvTitle->Brush->Color = clRed;
cnvTitle->Pen->Color = clRed;
cnvTitle->Ellipse(2, 2, 20, 20);
}
if(CvsConnection->CamStatusData[Cam - FCvsConnection->FirstCam].InfoActive)
{
cnvTitle->Brush->Style = bsSolid;
cnvTitle->Brush->Color = clLime;
cnvTitle->Pen->Color = clLime;
cnvTitle->Ellipse(24, 2, 44, 20);
};
// добавляем на hdcSrc информацию о статусе:
::TransparentBlt(
hdcSrc,
0,
0,
Width,
24,
hdcTitle,
0,
0,
Width,
24,
clBlack
);
cnvTitle->Unlock();
delete cnvTitle;
DeleteObject(hbmTitle);
DeleteDC(hdcTitle);
// отображаем результат на hdcDst:
BitBlt(
hdcDst,
0,
0,
Width,
Height,
hdcSrc,
0,
0,
SRCCOPY
);
cnvSrc->Unlock();
Canvas->Unlock();
delete cnvSrc;
DeleteObject(hbmSrc);
DeleteDC(hdcSrc);
};
}
Исключение небось
Код:
pCvsConnection->pLockStructures->Acquire();
не совсем корректно, потому что pCvsConnection тоже надо защищать.
Поэтому во вложенном классе добавил одноименную ссылку на pLockStructures,
которая инициализируется в его конструкторе.
Во вторых в классе TCvsCamera надо было добавить собственную TCriticalSection,
чтобы нормально отрабатывал этот кусок:
Код:
if(CvsConnection->CamStatusData[Cam - FCvsConnection->FirstCam].InfoAlarm)
...
...
так как тут есть обращение к FCvsConnection из основного и дополнительного потоков.
Правда не обошлось без изврата =)
Код:
void __fastcall TCvsCamera::SetCvsConnection(TCvsConnection *CvsConnection)
{
pCvsCameraCS->Acquire();
try {
TCvsConnection *OldCvsConnection = FCvsConnection;
FCvsConnection = CvsConnection;
if(FCvsConnection)
{
if(OldCvsConnection)
OldCvsConnection->UnRegisterCvsCameraComponent(this);
FTitle = FCvsConnection->CamName[FCam];
FCvsConnection->RegisterCvsCameraComponent(this);
}
else
if(OldCvsConnection)
{
pCvsCameraCS->Release();
try {
OldCvsConnection->UnRegisterCvsCameraComponent(this);
}
__finally {
pCvsCameraCS->Acquire();
};
};
Active = false;
}
__finally {
pCvsCameraCS->Release();
};
}
{
pCvsCameraCS->Acquire();
try {
TCvsConnection *OldCvsConnection = FCvsConnection;
FCvsConnection = CvsConnection;
if(FCvsConnection)
{
if(OldCvsConnection)
OldCvsConnection->UnRegisterCvsCameraComponent(this);
FTitle = FCvsConnection->CamName[FCam];
FCvsConnection->RegisterCvsCameraComponent(this);
}
else
if(OldCvsConnection)
{
pCvsCameraCS->Release();
try {
OldCvsConnection->UnRegisterCvsCameraComponent(this);
}
__finally {
pCvsCameraCS->Acquire();
};
};
Active = false;
}
__finally {
pCvsCameraCS->Release();
};
}
Чтобы сделать вызов 'OldCvsConnection->UnRegisterCvsCameraComponent(this);',
пришлось приоткрыть блокировку, может это и нормально )
Ну и одну секцию в поток TCvsConnection::TAlarm, который я тут не расписывал.
Это уже из-за расшаривания CamStatusData.
Теперь работает =)
А то что я описывал в первом посте видимо было следствием разрушения данных.