2016-09-30 2 views
0

릴리스 구성 (x86 및 x64 모두)으로 컴파일하면 프로그램이 완료되지 않습니다. 명확히하기 위해 빌드 오류나 실행 오류가 없습니다.릴리스 구성에서 다중 스레딩이있는 Visual Studio C++ 런타임 문제

문제의 원인과 해결책을 찾은 후 배열 문제라고 제안하는 Program only crashes as release build -- how to debug?을 발견했습니다. 이 문제가 내 문제를 해결했지만 문제에 대한 통찰력을주었습니다.

문제를 더 혼란스럽게하기 위해 메인 스레드의 서브 루틴의 실행 시간이 약 0ms보다 큰 경우에만 해당됩니다. 여기

코드의 관련 부분은 다음과 같습니다

내 프로그램에 걸리면 문제가되는 라인이 프로그램은 생성 된 스레드를 대기 마지막 문, 종료 할 수 있다는 것입니다
// Startup Progress Bar Thread 
nPC_Current = 0; // global int 
nPC_Max = nPC; // global int (max value nPC_Current will reach) 

DWORD myThreadID; 
HANDLE progressBarHandle = CreateThread(0, 0, printProgress, &nPC_Current, 0, &myThreadID); 

/* Do stuff and time how long it takes (this is what increments nPC_Current) */ 

// Wait for Progress Bar Thread to Terminate 
WaitForSingleObject(progressBarHandle, INFINITE); 

:

WaitForSingleObject(progressBarHandle, INFINITE); 

그리고 여기가 진행 표시 줄 기능을위한 코드입니다

DWORD WINAPI printProgress(LPVOID lpParameter) 
{ 
    int lastProgressPercent = -1; // Only reprint bar when there is a change to display. 

    // Core Progress Bar Loop 
    while (nPC_Current <= nPC_Max) 
    { 
     // Do stuff to print a text progress bar 
    } 
    return 0; 
} 

W 여기서 'Core'while 루프는 일반적으로 측정 된 서브 루틴의 실행 시간이 약 0ms이면 단일 반복을 얻지 못합니다. 이를 명확히하기 위해 timed 서브 루틴의 실행 시간이 약 0ms이면 printProgressBar가 한 번 실행되기 전에 nPC_Current가 nPC_Max보다 커집니다. 즉, 스레드가 주 스레드가 스레드를 기다리기 전에 종료됩니다.

누구든지이 문제에 도움이되거나 문제에 대한 추가 통찰력을 제공하면 문제를 해결하는 데 큰 어려움이 있습니다.

감사합니다.

편집 :

  • 표현은
  • 는 내용을 산만을 삭제하고 해명을
+0

Ooooooo! 나는 이것들을 싫어한다! 릴리스 코드는 디버그 코드와는 분명히 다릅니다. 디버그 빌드에서 작동하는 (또는 작동하는 것처럼 보이는) 무언가는 릴리스 빌드에 존재하지 않게 최적화되어 있으며 다르게 초기화되고 다른 코드 경로를 사용하거나 논리적 결함을 드러내는 방식으로 재 조립됩니다. 너를 위해서 느낀다, 재커리.하지만 이런 경우에는 보통 우리가 할 수있는 일이별로 없다. MCVE를 빌드하는 것은 절대 <숨겨진 삭제>가 될 것입니다. 그러나 위쪽에는 대개 버그가 노출되어 재 게시에서 제외됩니다. – user4581301

+0

"내 프로그램을 완료하지 못했습니다"란 의미는 무엇입니까? _Debug_ 모드에서 빌드하면 모든 것이 정상적으로 작동합니까? 실제로 어떤 일이 발생합니까? – CristiFati

+0

시도해 볼만한 한 가지는 오래된 체크 포인트 디버깅입니다. 몇 가지'std :: cerr' 문을 열어서'printProgress'에서 코드가 멈춰있는 곳을 찾으십시오. – user4581301

답변

6

내 생각에 공유 전역 변수 volatile (특히 nPC_Current)을 선언하는 것을 잊었을 것입니다.스레드 함수 자체가 nPC_Current을 수정하지 않기 때문에 코드의 릴리스 버전에서 컴파일러는 진행 막대 막대를 무한 루프로 최적화하여 nPC_Current 값을 절대로 변경하지 않았습니다.

이 때문에 진행률 표시 줄이 코드의 릴리스 버전에서 0% 값으로 업데이트되지 않으므로 진행률 표시 줄 스레드가 종료되지 않는 이유가 여기에 있습니다.

P. 또한 원래 nPC_Current 카운터를 스레드 매개 변수 (스레드 CreateThread 호출로 판단)로 스레드 함수에 전달하려고했던 것으로 보입니다. 그러나 스레드 함수에서는 매개 변수를 무시하고 nPC_Current에 전역 변수로 직접 액세스합니다. 스레드 매개 변수로 전달하고 액세스한다는 원래 아이디어에 충실하는 것이 더 좋은 아이디어 일 수 있습니다.

+0

See, 나는 "nPC_Current가 시간이 지남에 따라 계속 증가한다는 보장은 무엇입니까?"라고 물었습니다. 왜 그렇게하지 않았는지 정확한 기술적 인 이유를 발견했습니다. –

+0

감사합니다. 그냥 테스트 해본 결과 저에게 효과적이었습니다! – Zackary

-1
당신은 릴리스의 중단 점 (일부 제한 사항)를 사용할 수 있습니다

...

의이 부분을합니까 추가 코드 :

/* Do stuff and time how long it takes (this is what increments nPC_Current) */ 

스레드에 따라 달라질 수 있습니다. printProgress? (그렇다면 시간 의존성을 보장하고 편리하게 주문해야합니다.) 항상이 값이 항상 nPC_Current으로 증가하고 있습니까? 시간 의존 알고리즘입니까? Sleep()에 대한 영향을 테스트 했습니까?

는 쓰기 소프트웨어의 숫자 하나의 규칙은
+0

이것은 아무것도 대답하지 않습니다. 의견에 명확한 설명을 요청하십시오. – user4581301

+0

그 반대는 종속성에 해당합니다. printProgress는 'stuff'가 수행하는 작업에 영향을받습니다. 그리고 항상 nPC_Current를 늘리는 것이 확실합니다 (이것은 철저히 테스트되었습니다). 알고리즘은 또한 시간이 지나치다. 시간이 걸렸다는 것을 알기 위해 시간을 측정하고 싶었다. 잠도 잘 수 있었지만 지체없이 무언가를 찾고있었습니다. – Zackary

+0

@Zackary, 그 의존성은 분명합니다, 나는 그 반대를 요구하고있었습니다 : '물건'이 printProgress의 영향을 받습니까? –

1

없습니다 : 기회에

남기기 아무것도; 가능한 모든 오류가 있는지 확인하십시오 ().

참고 :이 숫자 하나의 규칙 하지 소프트웨어 문제 해결; 말썽이있을 때, 이미 너무 늦다; 이것은 소프트웨어를 쓰는 것, 즉 문제를 해결할 필요가 있기 전의 가장 중요한 규칙입니다.

코드에 여러 가지 문제가 있습니다. 나는 그것들 중 어느 것이 당신에게 당신이 겪고있는 문제를 일으키는 지 확실히 말할 수는 없지만 만약 당신이 그것들을 고치면 그것을 내기를 기꺼이 할 것입니다. 그리고 당신이 그러한 문제를 고치는 정신력을 개발한다면, 당신은 겪고있는 문제가 없습니다.

  1. WaitForSingleObject에 대한 문서는 말한다

    : "이 핸들이 닫혀있는 경우 대기는 아직 보류 상태에서, 함수의 동작은 정의되지 않습니다." 그러나 CreateThread()이 유효한 핸들을 반환했다고 주장하는 것처럼 보이지는 않습니다. 당신은 우리가 어디에서 그리고 어떻게 그 핸들을 닫고 있는지를 보여주지 못합니다. (그리고 핸들을 닫을 때 CloseHandle()이 실패하지 않았다고 주장합니까?)

  2. 글로벌 변수를 사용하고있을뿐만 아니라 (내가 강력히 권고하는 내용 일뿐만 아니라) 그 가정들 중 어느 하나를 주장하지 않고 그들의 가치에 관한 많은 가정들.

    • 기능의 시작 부분에서 nPC_Current가 실제로 nPC_Max보다 작은 것을 어떻게 보장합니까?

    • nPC_Current가 시간이 지남에 따라 계속 증가한다는 것을 어떻게 보장합니까?

    • lastProgressPercent의 계산이 루프 중에 -1을 실제로 유지하지 않는다는 것을 어떻게 보장합니까?

    • 보장 사항 nPC_Max가 이 아니고이 아닙니다. (별도의 스레드에서 0으로 나누기는 하드의 종류 잡을 수 있습니다.)

    • 당신이 당신의 스레드가 실행되는 동안 nPC_Max는 또한 수정하지 않는 것을 가지고 무엇을 보장?

    • nPC_Current가 원자 적으로 증가하는 것을 어떻게 보장합니까? (나는 당신이 원자 적으로 증가되지 않는 경우에, 당신은 다른 스레드에서 읽어 순간, 당신은 쓰레기를 읽을 수 있음을 이해 바랍니다.)

당신은 [C++]으로이 질문을 태그 한 몇 가지 C++ 기능이 사용되는 것을 보았습니다. 그러나 실제로 객체 지향 프로그래밍을 보지 못했습니다. 스레드 함수는 LPVOID 매개 변수를 정확하게 받아들이므로 객체를 전달할 수 있고 따라서 캡슐화와 같은 모든 이점을 포함하여 두 번째 스레드에서 객체 지향을 계속할 수 있습니다. 나는 당신이 그것을 사용하는 것이 좋습니다 것입니다.

+1

당신은 몇 가지 유효한 포인트를 가지고 있었고 실제로 프로젝트를 수정하여 원래의 문제가 존재하지 않았다고 생각했습니다. 그래서 고마워. 편집 : 주로 전역 전역에 대한 구조체를 만들었고 현재 인수를 인수로 전달하여 상태를 보증하기가 더 쉽습니다. – Zackary

관련 문제