C #에서는 메인 UI 스레드뿐만 아니라 두 개의 스레드가 필요한 스레딩을 실제로 사용한 적이 없습니다. 기본적으로 다음과 같은 것이 있습니다.
public void StartTheActions()
{
//Starting thread 1....
Thread t1 = new Thread(new ThreadStart(action1));
t1.Start();
// Now, I want for the main thread (which is calling `StartTheActions` method)
// to wait for `t1` to finish. I've created an event in `action1` for this.
// The I wish `t2` to start...
Thread t2 = new Thread(new ThreadStart(action2));
t2.Start();
}
따라서 본질적으로 내 질문은 스레드가 다른 스레드가 끝날 때까지 기다리는 방법입니다. 가장 좋은 방법은 무엇입니까?
답변
5 가지 옵션을 사용할 수 있습니다.
1. 스레드. 조인
미치의 대답과 마찬가지로. 그러나 이것은 UI 스레드를 차단하지만 타임 아웃이 내장되어 있습니다.
2. 사용 WaitHandle
ManualResetEvent
이다 WaitHandle
제안 jrista으로는.
WaitHandle.WaitAll()
MTA 스레드가 필요하기 때문에 여러 스레드를 대기하려는 경우 기본적으로 작동하지 않습니다. Main()
방법을 표시 하여이 문제를 해결할 수 MTAThread
있지만 메시지 펌프를 차단하므로 읽은 내용에서 권장하지 않습니다.
3. 이벤트를 시작
참조 존 소총으로이 페이지 이벤트 및 멀티 스레딩에 대한을,이 이벤트가 사이 unsubcribed이 될 수 있다는 가능성 if
과 EventName(this,EventArgs.Empty)
– 그 전에 나에게 일어난.
(다행 스럽게도이 컴파일은 시도하지 않았습니다)
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread1 = new Thread(worker.Run);
thread1.Start();
_count = 1;
}
void HandleThreadDone(object sender, EventArgs e)
{
// You should get the idea this is just an example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread2 = new Thread(worker.Run);
thread2.Start();
_count++;
}
}
class ThreadWorker
{
public event EventHandler ThreadDone;
public void Run()
{
// Do a task
if (ThreadDone != null)
ThreadDone(this, EventArgs.Empty);
}
}
}
4. 대리인 사용
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
Thread thread1 = new Thread(worker.Run);
thread1.Start(HandleThreadDone);
_count = 1;
}
void HandleThreadDone()
{
// As before - just a simple example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
Thread thread2 = new Thread(worker.Run);
thread2.Start(HandleThreadDone);
_count++;
}
}
class ThreadWorker
{
// Switch to your favourite Action<T> or Func<T>
public void Run(object state)
{
// Do a task
Action completeAction = (Action)state;
completeAction.Invoke();
}
}
}
_count 메소드를 사용하는 경우 다음을 사용하여 늘리는 것이 안전 할 수 있습니다.
Interlocked.Increment(ref _count)
스레드 알림을 위해 델리게이트와 이벤트를 사용하는 것의 차이점을 알고 싶습니다. 알고있는 유일한 차이점은 이벤트가 동 기적으로 호출된다는 것입니다.
5. 대신 비동기 적으로 수행
에 대한 대답 이 질문은 이 방법으로 옵션의 아주 명확한 설명이 있습니다.
잘못된 스레드의 델리게이트 / 이벤트
이벤트 / 델리게이트 방식은 이벤트 핸들러 메소드 가 기본 UI 스레드가 아닌 thread1 / thread2에 있음 을 의미 하므로 HandleThreadDone 메소드의 맨 위에서 오른쪽으로 다시 전환해야합니다.
// Delegate example
if (InvokeRequired)
{
Invoke(new Action(HandleThreadDone));
return;
}
답변
더하다
t1.Join(); // Wait until thread t1 finishes
시작한 후에는 메인 스레드에서 실행하는 것과 본질적으로 동일한 결과이므로 많은 것을 달성하지 못합니다!
.NET의 스레딩에 대한 이해를 얻으려면 C # 무료 전자 책 에서 Joe Albahari의 스레딩을 읽는 것이 좋습니다 .
답변
앞의 두 가지 대답은 훌륭하며 간단한 시나리오에서 작동합니다. 그러나 스레드를 동기화하는 다른 방법이 있습니다. 다음도 작동합니다.
public void StartTheActions()
{
ManualResetEvent syncEvent = new ManualResetEvent(false);
Thread t1 = new Thread(
() =>
{
// Do some work...
syncEvent.Set();
}
);
t1.Start();
Thread t2 = new Thread(
() =>
{
syncEvent.WaitOne();
// Do some work...
}
);
t2.Start();
}
ManualResetEvent 는 .NET 프레임 워크가 제공 해야하는 다양한 WaitHandle 중 하나입니다 . lock () / Monitor, Thread.Join 등과 같은 단순하지만 매우 일반적인 도구보다 훨씬 풍부한 스레드 동기화 기능을 제공 할 수 있습니다. 또한 ‘마스터’스레드와 같은 복잡한 시나리오를 허용하는 두 개 이상의 스레드를 동기화하는 데 사용할 수 있습니다. 여러 ‘하위’스레드, 서로 동기화 될 여러 단계에 종속 된 여러 동시 프로세스 등을 조정하는 등
답변
.NET 4에서 사용하는 경우이 샘플이 도움이 될 수 있습니다.
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Factory.StartNew(() => doStuff());
Task task2 = Task.Factory.StartNew(() => doStuff());
Task task3 = Task.Factory.StartNew(() => doStuff());
Task.WaitAll(task1, task2, task3);
Console.WriteLine("All threads complete");
}
static void doStuff()
{
//do stuff here
}
}
답변
Thread.Join()
메소드 또는 과부하 중 하나를 원합니다 .
답변
메인 스레드가 첫 번째 스레드에 콜백 메소드를 전달하도록하고, 완료되면 메인 스레드에서 콜백 메소드를 호출하여 두 번째 스레드를 시작할 수 있습니다. 이렇게하면 Join 또는 Waithandle을 기다리는 동안 주 스레드가 중단되지 않습니다. 어쨌든 C #으로 배우는 데 유용한 메서드를 대리자로 전달하는 것이 좋습니다.
답변
이 시도:
List<Thread> myThreads = new List<Thread>();
foreach (Thread curThread in myThreads)
{
curThread.Start();
}
foreach (Thread curThread in myThreads)
{
curThread.Join();
}
