|
COM port제어시 특정한 에러가 나지 않고 CPU사용율이 100%가 되는 경우는
대개가 CriticalSection의 할당이나 기타 자원할당등의 이벤트를 기다리는 코드가 무한반복되는 경우입니다.
해당 컴포넌트가 안정적인 녀석인진 써보지 않아서 잘 모르겠구요.
낡은 RS232c 나 USB 제어 컴포넌트들은 Thread safe하지 않은 코드들이 난무하는터라 신뢰하지 않습니다.
아래의 코드에도 좀 이상한 부분들이 있군요.
ReceiveBuf = (char *)pBuffer; <- pBuffer는 char *타잎인데도 char *로 캐스팅하고 계시군요 쓸모없습니다.
if(ReceiveBuf2!= "") <- ReceiveBuf2가 AnsiString 타잎처럼 문자열 비교연산을 특별히 지원하지 않는다면
당연히 pBuffer 는 지역변수인 스택에 위치하고 "" 인 NULL Terminated String은 리터럴 영역에 존재하거나
설정에 따라 특정 주소값에 할당되어 있을것이므로 항상 true가 되는 구문입니다.
즉 strcmp 함수를 쓰시거나 AnsiString 타잎으로 캐스팅(원래 AnsiString 타잎이었다면 문제 없습니다)
하셔야 할겁니다. (사실 이경우 *pBuffer != NULL 한방이면 끝나는거였습니다.)
그리고 문제가 되는게
pBuffer를 동적 할당하고 계신데,
동적할당후 해제 전에 Memo컴포넌트에 내용을 업데이트 하고 계신걸로 보이는군요.
이게 두 가지 문제가 있습니다.
만약 이 ApdComPort1TriggerAvail 함수가 쓰레드로 부터 호출되는 구조라면(Callback처럼)
VCL 컴포넌트들은 ThreadSafe하지 않으므로, Synchronize같은 함수를 통해 호출되었어야 합니다.
이부분은 사용하시는 ApdComPort 의 메뉴얼을 보시던가, 아니면 알 수 없는 부분이지만,
메모장같은게 아닌 파일로 덤프하시거나 하는 방법으로 VCL사용을 배제해 보시고 에러가 나지 않는다면
VCL ThreadFailure 라고 보시면 되겠죠.
또 한가지 문제는, Memory Fragmentation 입니다.
버퍼할당후 VCL에 업데이트 했다는 말은,
VCL 컴포넌트에 (메모장) 문자열이 추가되었단 말이고, 그 말은 메모리의 또다른 동적 할당을 의미하죠.
즉 [pBuffer할당메모리][ Memo할당메모리] 이런 구조로 힙영역에 적재 될꺼란겁니다.
그 후 메모는 해제 되지 않은채 pBuffer는 delete되고 있는 구조죠
즉, [해제된 사용가능영역][Memo할당메모리] 처럼 되는데
이렇게 짜실 짜실하게 해제된 영역과 할당된 영역이 스트라이핑 되는 경우,
이미 해제된 사용가능영역보다 큰 메모리는 할당 불가가 되는 사태가 생길 수 있습니다.
즉, 전체 메모리가 1기가가 남았다 하더라도
1바이트씩 사이사이에 Memo장에 할당된 문자들이 끼어서
조각난 사용가능 메모리의 크기가 1메가 단위라면,
1메가 이상되는 메모리는 할당할 수 없는 메모리 단편화 문제가 생긴다는겁니다.
이런 경우, pBuffer를 미리 스택에서 크기를 고정해 놓고 사용하고,
그 크기보다 크게 들어오는 경우 계속 잘라서 메모에 덤프 시키는 식으로 전환하시는게
안전한 방법이실겁니다.
스택에다가 메모리를 할당한다는것은, 별도의 할당 메카니즘이 있다기 보다,
스택포인터의 위치를 끌어올리는 단 한번의 대입으로 완료되는 메카니즘이므로,
성능도 올라가게 됩니다.
크기를 예측할 수 없을때 동적할당을 쓰곤 하시는데...
어차피 시스템에서 사용할 수 있는 메모리의 양은 제한이 있으므로 메모리풀을 만드는 방법이
더 좋은 해결책이 되겠죠.
그게 귀찮으면 스택으로 가는겁니다.
조윤상 님이 쓰신 글 :
: 안녕하세요...
: 제가 Async Pro ApdComPort를 이용해서 Terminal을 만들었는데요
: 사용 중 문제가 있어 질문드립니다.
:
: 장비2대가 연결되있고 PC는 한대입니다.
: PC에 Terminal창 두개 만들고 ApdComPort도 두개 만들었는데 실행중 문제가
: 있습니다.
:
: 문제1.
: 처음 실행후 얼마동안은 작동이 잘되다가 어느순간 Terminal화면이 멈춰버리고
: 키도 입력이 안됩니다. 그러다 끊고 다시 연결하면 또 잘됩니다.
:
: 문제2.
: 어느순간 CPU사용률이 100%되면서 프로그램이 죽어있는것처럼 됩니다.
:
: 제 생각에는 콤포넌트 내부Buffer를 사용하면서 지우지 않아서 생기는 현상 같습니다.
: 혹시 몰라 소스첨부합니다.
:
: //장비1의 TriggerAvail이벤트 함수:
: void __fastcall TMrTerminalMainForm::ApdComPort1TriggerAvail(TObject *CP,
: WORD Count)
: {
: char* pBuffer ;
:
: try
: {
: ReceiveBufLen = Count;
: if(ReceiveBufLen <= 0 )
: {
: ApdComPort1->Open = false;
: return;
: }
: pBuffer = new char[Count] ;
: memset(pBuffer, 0, sizeof(pBuffer));
:
: for (int i=0;i<Count;i++)
: {
: pBuffer[i] = ApdComPort1->GetChar();
: }
:
: ReceiveBuf = (char *)pBuffer;
:
: if(ReceiveBuf != "") //if(pBuffer != NULL)
: AddToMemo();
: }
: __finally
: {
: delete[] pBuffer;
: }
: }
: //---------------------------------------------------------------------------
:
: //장비2의 TriggerAvail이벤트 함수:
: void __fastcall TMrTerminalMainForm::ApdComPort2TriggerAvail(TObject *CP,
: WORD Count)
: {
: char* pBuffer2;
:
: try
: {
:
: ReceiveBufLen2= Count;
:
: if(ReceiveBufLen2<= 0 )
: {
: ApdComPort2->Open = false;
: return;
: }
: pBuffer2= new char[Count] ;
:
: memset(pBuffer2, 0, sizeof(pBuffer2));
:
: for (int i=0;i<Count;i++)
: {
: pBuffer2[i] = ApdComPort2->GetChar();
: }
:
: ReceiveBuf2= (char *)pBuffer2;
:
: if(ReceiveBuf2!= "")
: AddToMemo2();
:
: }
: __finally
: {
: delete[] pBuffer2;
: }
:
: }
: //---------------------------------------------------------------------------
|