2010-02-21 3 views
10

보고서 모드에서 ListView가있는 Windows Form이 있습니다. 뷰의 각 항목에 대해 장기 실행 작업을 수행해야하며 그 결과는 숫자입니다.MsgWaitForMultipleObjects와 동일한 C#은 무엇입니까?

네이티브 win32에서이 작업을 수행하는 방법은 각 항목에 대해 작업자 스레드를 만드는 것입니다 (당연히 나는 무제한의 스레드를 만들지 않습니다). 그런 다음 스레드 핸들 배열에 MsgWaitForMultipleObjects()를 작성합니다. 각 계산이 끝나면 스레드 신호와 기본 UI 스레드가 깨어나서 업데이트됩니다. 그 동안 UI 스레드가 응답 할 수 있도록 메시지를 전달합니다.

누구나 C#에서 어떻게 작동하는지 예제를 제공 할 수 있습니까? Monitor 개체를 살펴본 결과, 원하는대로 보이지 않거나 차단하는 동안 메시지를 보내지 않습니까?

감사합니다.

편집 : WaitHandler.WaitAny()가 실제로 메시지를 보내고있는 것으로 보입니다. CLR의 메시지 펌핑에 대해서는 cbrumme's treatise을 참조하십시오.

+0

맞습니다. 모니터가 메시지를 보내지 않습니다. WaitHandle이 더보기 좋은 장소 일 수도 있지만 메시지를 펌핑하는 WaitHandle 메서드를 찾을 수 없습니다. – itowlson

+0

그래, 나도 그걸 봤어. 여러 객체를 기다릴 필요가 없습니다. 하나의 이벤트 나 다른 것을 기다리는 데 걸릴 것입니다. UI를 차단하고 싶지 않습니다. 내가 찾은 모든 샘플은 '슬립 (sleep) (100)'이나 문맥 전환을 강제하는 무언가를합니다. 이것은 매우 슬픈 일입니다. –

+0

WinForms에서 메시지 루프가 명확하지 않다는 것이 문제라고 생각합니다. 따라서 MsgWaitX를 직접 수행 할 수 없으므로 대신 이벤트를 발생시킬 수있는 무언가가 필요합니다. 예를 들어, 각 하위 작업을 BackgroundWorker로 실행하십시오 (sync 프리미티브는 잊어 버리십시오). – itowlson

답변

2

장기 실행 액티브 오브젝트는 귀하의 경우에 최선의 선택이라고 생각합니다. 주 스레드는 (활성 객체의) 프록시를 호출합니다. 프록시는 호출 메소드를 메세지로 변환하며이 메세지는 대기 행렬에 있습니다. 프록시는 호출자에게 미래 객체를 반환합니다 (이는 미래 결과에 대한 참조 임). 디스패처는 메시지를 하나씩 대기열에서 제외하고 다른 스레드 (작업 스레드)에서 실제로 작업을 실행합니다. 작업 스레드가 작업을 완료하면 향후 개체의 결과를 업데이트하거나 콜백 메서드를 호출합니다 (예 : UI 업데이트) .Dispather는 동시에 하나의 작업을 더 많이 실행하는 많은 작업 스레드를 가질 수 있습니다.

장기 실행중인 개체 패턴에 대해 article (샘플 포함)을 볼 수 있습니다.

+0

정보에 대한 링크뿐만 아니라 일부 정보를 제공해주십시오. –

+0

흠, 그런 간단한 문제를 해결하기 위해 많은 코드가 필요할 것 같습니다. 내가 원한다면 나는 항상 내 자신의 COM 객체를 pinvoke 할 수있다. C# 프레임 워크가 충분히 성숙하지 못하면 쉽게 Win32 코드를 작성할 수 있습니다. 비록 나는 그들이 이것을 할 수있는 쉬운 방법이라고 믿어야 만합니다. –

+0

네, 맞습니다. 다음은 MSDN의 예제입니다. connection1.Open(); SqlCommand command1 = 새 SqlCommand (commandText1, connection1); IAsyncResult result1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; connection2.Open(); \t \t \t \t ... WaitHandle이 [] = {waitHandles의 waitHandle1, waitHandle2, waitHandle3 }; \t \t bool 결과 = WaitHandle.WaitAll (waitHandles, 60000, false); – garik

2

메인 스레드에서 관리자 스레드를 만듭니다. 이 경우 BackgroundWorker을 사용할 수 있습니다. 이 관리자 스레드는 ListView의 각 항목에 대한 작업자 스레드를 시작합니다. 이렇게하면 백그라운드 스레드가 처리되는 동안 UI가 응답하지 않고 사용자 입력에 계속 응답 할 수 있습니다.

이제 문제는 각 작업자 스레드가 완료 될 때까지 대기하는 방법입니다. 불행히도, 나는 System.Threading.Thread 개체에 대한 스레드 핸들을 얻을 수있는 방법을 찾을 수 없습니다. 나는 그것을 할 수있는 방법이 없다는 것을 말하는 것이 아닙니다. 나는 단지 하나를 찾지 못했다. 또 다른 복잡한 점은 System.Threading.Thread 클래스가 봉인되어 있기 때문에 어떤 종류의 '핸들'을 제공 할 수 없다는 것입니다.

여기는 ManualResetEvent입니다.

각 작업자 스레드가 단순히 ThreadPool 스레드라고 가정 해 보겠습니다. 관리 BackgroundWorker은 ListView의 각 항목에 대해 ManualResetEvent 개체를 만듭니다. BackgroundWorker이 각 ThreadPool 스레드를 시작하면 ManualResetEvent을 인수로 사용하여 QueueUserWorkItem function에 전달합니다. 그런 다음 각 ThreadPool 스레드가 종료되기 직전에 ManualResetEvent 개체를 설정하십시오.

BackgroundWorker 스레드는 ManualResetEvent 개체를 모두 배열에 넣고 WaitHandle.WaitXXX functions을 사용하여 해당 배열을 기다릴 수 있습니다. 각 스레드가 완료되면 BackgroundWorker의 이벤트를 사용하여 UI를 업데이트하거나 Control.Invoke() 기술을 사용하여 UI를 업데이트 할 수 있습니다 (Marc Gravell의 답변 here 참조).

희망이 도움이됩니다.

+0

메시지 전송 대기 시간을 계산할 수 없다면 이는 합리적인 방식으로 보입니다. 나는 하나가 없다는 것을 믿기가 정말 힘들다. 뭔가 발견하면 스레드를 업데이트 할 것입니다. –

관련 문제