如何在新线程中运行一小段代码?

326 .net c# multithreading

我有一些代码需要在与GUI不同的线程中运行,因为它当前导致表单在代码运行时冻结(10秒左右).

假设我以前从未创建过新的线程; 什么是如何在C#中使用.NET Framework 2.0或更高版本执行此操作的简单/基本示例?

Ed *_*wer 322

Joe Albahari是开始阅读的好地方.

如果你想创建自己的线程,这很简单:

using System.Threading;
new Thread(() => 
{
    Thread.CurrentThread.IsBackground = true; 
    /* run your code here */ 
    Console.WriteLine("Hello, world"); 
}).Start();
Run Code Online (Sandbox Code Playgroud)

  • @EdPower我认为你应该小心!您可能不希望在执行期间终止的任务的一个示例是将数据保存到磁盘的任务.但是可以肯定的是,如果您的任务适合随时终止,那么旗帜就可以了.我的观点只是*人们需要小心使用旗帜*,因为你没有描述它的目的,而且它的命名很容易让人相信它做的不是它实际做的事情. (6认同)
  • 将'IsBackground`设置为true时要小心.它可能不会做你认为它做的事情.它的作用是配置当所有前台线程都已经死亡时线程是否会被杀死,或者线程是否会使应用程序保持活动状态.如果您不希望线程在执行期间终止,请不要将`IsBackground`设置为true. (4认同)
  • 使用 .NET Framework 4.0+ 只需使用 Task.Run(),如本答案所述:/sf/answers/2224501471/ (4认同)

Gan*_*ant 192

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();
    }
Run Code Online (Sandbox Code Playgroud)

注意:

  • 为了简单起见,我使用C#的匿名方法将所有内容都放在单个方法中,但您总是可以将它们用于不同的方法.
  • 在内部ProgressChangedRunWorkerCompleted处理程序中更新GUI是安全的 .但是,更新GUI DoWork 将导致 InvalidOperationException.

  • 使用System.ComponentModel; (可能会使人们无法进行谷歌搜索,感谢这个有用的代码示例)+1 (26认同)

Mar*_*ett 99

ThreadPool.QueueUserWorkItem是相当理想的简单的东西.唯一需要注意的是从另一个线程访问一个控件.

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);
Run Code Online (Sandbox Code Playgroud)


Fal*_*tar 75

快速又脏,但它会起作用:

在顶部使用:

using System.Threading;
Run Code Online (Sandbox Code Playgroud)

简单代码:

static void Main( string[] args )
{
    Thread t = new Thread( NewThread );
    t.Start();
}

static void NewThread()
{
    //code goes here
}
Run Code Online (Sandbox Code Playgroud)

我把它扔进了一个新的控制台应用程序中

  • @CmdrTallen:那不太对劲.标记为IsBackground = true的线程意味着线程不会停止进程退出,即当所有IsBackground = false的线程退出时,进程将退出 (13认同)
  • 记住标记为IsBackground的线程不会被运行时自动终止.这需要应用程序进行线程管理.如果您将线程标记为非后台,则在线程执行后,线程将终止. (7认同)
  • -1.至少您需要将IsBackground设置为true. (3认同)

Spo*_*ade 62

这是另一种选择:

Task.Run(()=>{
//Here is a new thread
});
Run Code Online (Sandbox Code Playgroud)

  • 你想要的海绵bob的确切代码样本;-) (22认同)
  • @GiulioCaccin ThreadPool 可以从其池中选择一个现有线程,但它绝对是一个不同的线程。 (7认同)
  • 此代码不保证您有新线程.决定取决于您正在使用的ThreadPool的当前实现.参见示例/sf/ask/949940561/ (5认同)
  • @MohsenShakiba,我感兴趣为什么这可能不是最好的方法?它当然非常简洁(我已经使用了一段时间的方法). (3认同)

And*_*ndy 40

尝试使用BackgroundWorker类.您可以为代理人提供运行的内容,并在工作完成时收到通知.我链接到的MSDN页面上有一个示例.

  • @Merus,你能扩展一下那些微妙的限制吗? (9认同)
  • 您当然可以使用Thread类执行此操作,但BackgroundWorker为您提供了线程完成和进度报告的方法,否则您必须弄清楚如何使用自己.不要忘记你必须使用Invoke与UI交谈! (6认同)

小智 14

如果你想得到一个值:

var someValue;

Thread thread = new Thread(delegate()
            {                 
                //Do somthing and set your value
                someValue = "Hello World";
            });

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();
Run Code Online (Sandbox Code Playgroud)


Red*_*ron 6

将该代码放在一个函数中(无法在与GUI相同的线程上执行的代码),并触发该代码的执行,如下所示.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

在线程对象上调用start函数将导致在新线程中执行函数调用.

  • @ user50612你在说什么?新线程将在后台运行`nameOfFunction`,而不是在当前GUI线程上运行.`IsBackground`属性确定线程是否会使应用程序保持活动状态:https://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.110).aspx# ANCHOR_2 (3认同)

use*_*612 5

如果要使用原始 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()
}
Run Code Online (Sandbox Code Playgroud)

如果您需要 UI 交互,我会推荐 BackgroundWorker 类。


小智 5

在这里,如何将线程与progressBar结合使用,仅用于了解线程的工作方式,形式为三个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();
    }
}
Run Code Online (Sandbox Code Playgroud)