Re-entrancy로 Embarcadero CB10.1 문제를 처리하는 방법에 대한 조언을하고 싶습니다. "모든 최적화 비활성화"가 true로 설정된 디버그 구성으로 컴파일되었습니다. 나는 Win7에서 실행 중이다.Embarcadero C++ Builder에서 이벤트 핸들러가 재진입합니까?
간단한 테스트 케이스가 있습니다. 두 개의 단추가있는 폼. 각 단추의 OnClick 이벤트 처리기는 동일한 CPU 집중 기능을 호출합니다. 아래는 프로그램 파일이 뒤 따르는 헤더 파일입니다.
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TButton *Button2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private: // User declarations
double __fastcall CPUIntensive(double ButonNo);
double __fastcall Spin(double Limit);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Button1->Caption = "Pushed";
double retv = CPUIntensive(1);
Button1->Caption = "Button1";
if (retv) ShowMessage("Button1 Done");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Button2->Caption = "Pushed";
double retv = CPUIntensive(2);
Button2->Caption = "Button2";
if (retv) ShowMessage("Button2 Done");
}
//---------------------------------------------------------------------------
double __fastcall TForm1::CPUIntensive(double ButtonNo)
{
//
static bool InUse = false;
if (InUse) {
ShowMessage("Reentered by button number " + String(ButtonNo));
while (InUse) {};
}
double retv;
InUse = true;
retv = Spin(30000); // about 9 seconds on my computer
//retv += Spin(30000); // uncomment if you have a faster computer
//retv += Spin(30000);
InUse = false;
return retv;
}
//---------------------------------------------------------------------------
double __fastcall TForm1::Spin(double Limit)
{
double k;
for (double i = 0 ; i < Limit ; i++) {
for (double j = 0 ; j < Limit ; j++) {
k = i + j;
// here there can be calls to other VCL functions
Application->ProcessMessages(); // added so UI would be responsive (2nd case)
}
}
return k;
}
//---------------------------------------------------------------------------
- 1 일 경우 : 표시된 코드 만 ProcessMessages에 대한 호출없이().
이것을 실행하고 버튼 1을 클릭하면 CPU 사용량이 약 012 초에 최대 100 %로 점프합니다. 이 시간 동안 양식이 응답하지 않게됩니다. 양식을 이동하거나 버튼 2를 클릭 할 수 없습니다.
예상대로 작동합니다.
두 번째 경우 : CPU 집중 기능 중 사용자가 응답하는 양식을 만들기 위해 표시된대로 ProcessMessages() 호출을 추가했습니다. 이제 양식을 이동하고 다른 버튼을 클릭 할 수 있습니다.
버튼 1을 다시 클릭 할 수도 있고 버튼 2를 클릭하기 만해도 항상 좋은 것은 아닙니다. 클릭하면 CPU 집중 기능이 다시 실행됩니다. CPU 집약 함수가 두 번째로 실행되는 것을 방지하기 위해 정적 부울 플래그 "InUse"를 만들었습니다. 함수가 시작될 때 으로 설정하고 함수가 완료되면이를 지 웁니다.
그래서 CPU 집약 기능을 입력하면 버튼을 이전 클릭으로 설정해야합니다 ( ) 메시지를 표시하고 플래그가 지워질 때까지 기다리는 경우 플래그를 확인합니다.
하지만 플래그가 지워지지 않고 내 프로그램이 'while'문에서 반복적으로 실행됩니다. 나는이 프로그램이 CPU 집약 기능 이 완료 될 때까지 기다렸다가 다시 실행하기를 바란다.
교착 상태에 도달 한 후 Spin() 함수에서 중단 점을 설정하면 이벤트가 실행되지 않음을 나타내는 절대 실행되지 않습니다.
나는 VCL이 스레드로부터 안전하지는 않지만 여기서 모든 처리는 메인 스레드에서 을 차지한다는 것을 알고있다. 내 실제 코드에는 VCL 함수에 대한 호출이 많으므로 CPU 집약 함수가 기본 스레드 에 남아 있어야합니다.
중요한 부분과 뮤텍스를 고려했지만 모든 것이 메인 스레드에 있으므로 아무 것도 차단하지 않습니다.
아마도 스택 문제일까요? 교착 상태없이이 문제를 처리 할 수있는 솔루션이 있습니까?
이것은 단일 스레드 프로그램이므로'while (flag) {}; '라고 말하면 물론 영원히 반복됩니다. 다른 코드는 실행되고 있지 않으므로'flag '의 값이 어떻게 바뀔 수 있습니까? 중첩 호출에서 돌아와 외부 호출을 완료 할 수 있어야합니다. –
사용자가 버튼을 클릭 한 횟수만큼 작업을 실행하려면 카운터가 있어야합니다. 그러나 작업이 완료 될 때까지 두 버튼을 모두 비활성화하는 것이 더 현명 할 수 있습니다. –
[Delphi에서 Application.ProcessMessages가 수행하는 작업을 이해할 수 없음] 가능한 복제본 (http://stackoverflow.com/questions/25181713/i-do-not-understand-what-application-processmessages-in-delphis -doing) –