GUI가 아닌 다른 스레드에서 실행 해야하는 약간의 코드가 있습니다. 현재 코드가 실행되는 동안 (10 초 정도) 양식이 정지됩니다.
이전에 새 스레드를 만든 적이 없다고 가정합니다. C #에서 .NET Framework 2.0 이상을 사용하는 방법에 대한 간단한 / 기본 예는 무엇입니까?
GUI가 아닌 다른 스레드에서 실행 해야하는 약간의 코드가 있습니다. 현재 코드가 실행되는 동안 (10 초 정도) 양식이 정지됩니다.
이전에 새 스레드를 만든 적이 없다고 가정합니다. C #에서 .NET Framework 2.0 이상을 사용하는 방법에 대한 간단한 / 기본 예는 무엇입니까?
답변:
읽기 시작하기 좋은 곳은 Joe Albahari 입니다.
자신 만의 스레드를 만들고 싶다면 다음과 같이 간단합니다.
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
Console.WriteLine("Hello, world");
}).Start();
IsBackground
true로 설정하는 데 주의하십시오 . 아마도 당신이 생각하는 것을하지 않을 것입니다. 그 기능은 모든 포 그라운드 스레드가 사망했을 때 스레드가 종료되는지 또는 스레드가 애플리케이션을 계속 유지할지 여부를 구성하는 것입니다. 실행 도중 스레드가 종료되지 않게 IsBackground
하려면 true로 설정하지 마십시오 .
BackgroundWorker
최선의 선택 인 것 같습니다.
여기에 최소한의 예가 있습니다. 단추를 클릭하면 백그라운드 작업자가 백그라운드 스레드에서 작업을 시작하고 진행 상황을 동시에보고합니다. 작업이 완료된 후에도보고합니다.
using System.ComponentModel;
...
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
// this allows our worker to report progress during work
bw.WorkerReportsProgress = true;
// what to do in the background thread
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
// do some simple processing for 10 seconds
for (int i = 1; i <= 10; i++)
{
// report the progress in percent
b.ReportProgress(i * 10);
Thread.Sleep(1000);
}
});
// what to do when progress changed (update the progress bar for example)
bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
});
// what to do when worker completes its task (notify the user)
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
label1.Text = "Finished!";
});
bw.RunWorkerAsync();
}
노트 :
ProgressChanged
또는
RunWorkerCompleted
핸들러. 그러나 GUI를 업데이트 DoWork
하면에서 발생
InvalidOperationException
합니다.ThreadPool.QueueUserWorkItem는 뭔가 간단한 꽤 이상적입니다. 유일한주의 사항은 다른 스레드에서 컨트롤에 액세스하는 것입니다.
System.Threading.ThreadPool.QueueUserWorkItem(delegate {
DoSomethingThatDoesntInvolveAControl();
}, null);
빠르고 더럽지 만 작동합니다.
상단에 사용 :
using System.Threading;
간단한 코드 :
static void Main( string[] args )
{
Thread t = new Thread( NewThread );
t.Start();
}
static void NewThread()
{
//code goes here
}
방금 이것을 exmaple을위한 새로운 콘솔 응용 프로그램으로 던졌습니다.
다른 옵션은 다음과 같습니다.
Task.Run(()=>{
//Here is a new thread
});
BackgroundWorker 클래스를 사용해보십시오 . 실행할 대상을 위임하고 작업이 완료되면 알림을받습니다. 내가 링크 한 MSDN 페이지에 예가 있습니다.
해당 코드를 함수 (GUI와 동일한 스레드에서 실행할 수없는 코드)에 넣고 해당 코드의 실행을 트리거하려면 다음을 입력하십시오.
Thread myThread= new Thread(nameOfFunction);
workerThread.Start();
스레드 객체에서 시작 함수를 호출하면 새 스레드에서 함수 호출이 실행됩니다.
nameOfFunction
현재 GUI 스레드가 아닌 백그라운드에서 실행 됩니다. 이 IsBackground
속성은 스레드가 응용 프로그램을 유지할지 여부를 결정합니다. msdn.microsoft.com/en-us/library/…
다음은 progressBar와 함께 스레드를 사용하는 방법으로, 스레드가 작동하는 방식을 설명하기 위해 3 개의 progressBar 및 4 버튼이 있습니다.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread t, t2, t3;
private void Form1_Load(object sender, EventArgs e)
{
CheckForIllegalCrossThreadCalls = false;
t = new Thread(birinicBar); //evry thread workes with a new progressBar
t2 = new Thread(ikinciBar);
t3 = new Thread(ucuncuBar);
}
public void birinicBar() //to make progressBar work
{
for (int i = 0; i < 100; i++) {
progressBar1.Value++;
Thread.Sleep(100); // this progressBar gonna work faster
}
}
public void ikinciBar()
{
for (int i = 0; i < 100; i++)
{
progressBar2.Value++;
Thread.Sleep(200);
}
}
public void ucuncuBar()
{
for (int i = 0; i < 100; i++)
{
progressBar3.Value++;
Thread.Sleep(300);
}
}
private void button1_Click(object sender, EventArgs e) //that button to start the threads
{
t.Start();
t2.Start(); t3.Start();
}
private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
{
t.Suspend();
t2.Suspend();
t3.Suspend();
}
private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
{
t.Resume();
t2.Resume();
t3.Resume();
}
private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
{
t.Abort();
t2.Abort();
t3.Abort();
}
}
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
Charles (위) 코드가 올바르지 않습니다. 완료를 기다릴 필요가 없습니다. EndInvoke는 WaitHandle이 신호를 보낼 때까지 차단됩니다.
완료 될 때까지 차단하려면 간단히
nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));
또는 대안 적으로
ar.AsyncWaitHandle.WaitOne();
그러나 차단하면 anyc 호출을 발행하는 요점은 무엇입니까? 동기 호출을 사용할 수도 있습니다. 더 나은 방법은 정리를 위해 람다를 차단하고 전달하지 않는 것입니다.
nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);
명심 해야 할 것은 EndInvoke 를 호출 해야 한다는 것 입니다. 대부분의 비동기 구현이 EndInvoke에서 waithandle을 해제함에 따라 많은 사람들이 이것을 잊고 WaitHandle을 유출시킵니다.
원시 Thread 객체를 사용하려는 경우 IsBackground를 최소한 true로 설정해야하며 Threading Apartment 모델 (아마도 STA)도 설정해야합니다.
public static void DoWork()
{
// do some work
}
public static void StartWorker()
{
Thread worker = new Thread(DoWork);
worker.IsBackground = true;
worker.SetApartmentState(System.Threading.ApartmentState.STA);
worker.Start()
}
UI 상호 작용이 필요한 경우 BackgroundWorker 클래스를 권장합니다.
델리게이트와 스레드 풀을 사용하는 또 다른 옵션은 ...
'GetEnergyUsage'는 DateTime과 다른 DateTime을 입력 인수로 사용하고 Int를 반환하는 메서드라고 가정합니다.
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime,
DateTime procDateTime);
// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
int usageCnt = nrgDel.Invoke(lastRunTime, procDT, null, null);
가요? 어쨌든 수면 상태에서 현재 스레드를 일시 중단하는 것처럼 보입니다 ... GUI 스레드에서 호출하면 GUI가 멈추는 데 도움이되지 않는다고 생각했습니다.
.Net에서 별도의 스레드를 실행하는 방법은 여러 가지가 있으며 각 동작은 서로 다릅니다. GUI가 종료 된 후 스레드를 계속 실행해야합니까? 스레드와 GUI간에 정보를 전달해야합니까? 스레드가 GUI를 업데이트해야합니까? 스레드가 한 작업을 수행 한 다음 종료해야합니까, 아니면 계속 실행해야합니까? 이 질문에 대한 답변은 어떤 방법을 사용해야하는지 알려줍니다.
Code Project 웹 사이트에는 다양한 방법을 설명하고 샘플 코드를 제공 하는 좋은 비동기 방법 기사 가 있습니다.
이 기사는 async / await 패턴과 Task Parallel Library 가 .NET에 도입 되기 전에 작성 되었습니다.
다른 스레드에서 GUI 관련 항목에 액세스하는 데 매우주의해야합니다 (많은 GUI 툴킷에서 일반적 임). 처리 스레드에서 GUI에서 무언가를 업데이트하려면 이 답변 을 확인하십시오 .WinForms에 유용하다고 생각합니다. WPF의 경우이 내용을 참조 하십시오 (UpdateProgress () 메서드의 구성 요소를 터치하여 다른 스레드에서 작동하는 방법을 보여 주지만 실제로 Dispathcer를 통해 수행 CheckAccess()
하기 전에 수행 하지 않는 것이 마음에 들지 않습니다 BeginInvoke
.CheckAccess 참조 및 검색)
스레딩에 .NET의 특정 책을보고 발견 이 하나 (무료 다운로드)를. 자세한 내용은 http://www.albahari.com/threading/ 을 참조 하십시오 .
처음 20 페이지에서 새로운 스레드로 실행을 시작하는 데 필요한 것을 찾을 수 있다고 생각합니다. 더 많은 스레드가 있습니다 (스레딩에만 엄격하게 적용되는 GUI 특정 스 니펫에 대해서는 확실하지 않습니다). 내가이 글을 읽고 있기 때문에이 작업에 대해 커뮤니티가 어떻게 생각하는지 들으면 기쁠 것입니다. 지금은 나에게 깔끔하게 보였다 (스레딩에 대한 .NET 특정 메소드 및 유형 표시). 또한 .NET 2.0 (그리고 고대 1.1은 아님)에 대해 정말로 감사합니다.
Jeff Richter의 Power Threading Library 와 특히 IAsyncEnumerator를 살펴 보는 것이 좋습니다 . 의 비디오를 살펴보세요 찰리 칼 버트의 리히터 좋은 개요를 위해 위에 어디로 블로그.
비동기 프로그래밍 작업을 쉽게 코딩 할 수 있기 때문에 이름을 사용하지 마십시오.