Как запустить простой бит кода в новом потоке?

У меня есть немного кода, который мне нужно запустить в другом потоке, чем в графическом интерфейсе, поскольку он в настоящее время заставляет форму замораживаться, пока код работает (10 секунд или около того).

Предположим, что я еще никогда не создавал новый поток; какой простой/базовый пример того, как это сделать на С# и с использованием .NET Framework 2.0 или новее?

Ответ 1

Хорошее место для начала чтения - Joe Albahari.

Если вы хотите создать свой собственный поток, это будет так просто, как это получается:

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

Ответ 2

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();
    }

Примечание:

  • Я помещаю все в один метод используя анонимный метод С# для простота, но вы всегда можете их к различным методам.
  • Безопасно обновлять GUI в пределах ProgressChanged или RunWorkerCompleted. Однако обновление GUI из DoWork приведет к InvalidOperationException.

Ответ 3

ThreadPool.QueueUserWorkItem довольно хорош для чего-то простого. Единственное предупреждение - доступ к элементу управления из другого потока.

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);

Ответ 4

Быстро и грязно, но он будет работать:

Использование сверху:

using System.Threading;

простой код:

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

static void NewThread()
{
    //code goes here
}

Я просто бросил это в новое консольное приложение для exmaple

Ответ 5

Вот еще один вариант:

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

Ответ 6

Попробуйте использовать класс BackgroundWorker. Вы даете ему делегатов за то, что нужно запускать, и чтобы они были уведомлены о завершении работы. На странице MSDN, с которой я связан, есть пример.

Ответ 7

Если вы хотите получить значение:

var someValue;

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

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();

Ответ 8

Поместите этот код в функцию (код, который не может быть выполнен в том же потоке, что и GUI), и для запуска этого выполнения кода поставьте следующее.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Вызов функции запуска объекта потока приведет к выполнению вызова функции в новом потоке.

Ответ 9

// 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);

Ваш код (см. выше) неверен. Вам не нужно отжимать ожидание завершения. EndInvoke будет блокироваться до тех пор, пока не будет сигнализирован WaitHandle.

Если вы хотите заблокировать до завершения, вам просто нужно

nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));

или, альтернативно,

ar.AsyncWaitHandle.WaitOne();

Но какой смысл выдавать вызовы anyc, если вы блокируете? Вы можете просто использовать синхронный вызов. Лучше было бы не блокировать и пропускать лямбду для очистки:

nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);

Следует иметь в виду, что вы должны называть EndInvoke. Многие люди забывают об этом и заканчивают утечку WaitHandle, поскольку большинство реализаций async освобождают waithandle в EndInvoke.

Ответ 10

Если вы собираетесь использовать необработанный объект Thread, вам нужно установить значение IsBackground как минимум, и вы также должны установить модель 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()              
    }

Я бы рекомендовал класс BackgroundWorker, если вам нужно взаимодействие с пользовательским интерфейсом.

Ответ 11

Здесь, как использовать потоки с 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();
    }
}

Ответ 12

другой вариант, который использует делегаты и пул потоков...

Предполагая, что 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);

Ответ 13

Как использовать фоновый поток для поиска файлов

Вы должны быть очень осторожны с доступом из других потоков к конкретным материалам GUI (это распространено для многих наборов инструментов GUI). Если вы хотите что-то обновить в графическом интерфейсе от обработки потока, проверьте этот ответ, который, как мне кажется, полезен для WinForms. Для WPF см. this (он показывает, как коснуться компонента в методе UpdateProgress(), чтобы он работал из других потоков, но на самом деле я не как это не делает CheckAccess() перед тем, как делать BeginInvoke через Dispathcer, см. и искать CheckAccess в нем)

Посмотрел конкретную книгу .NET на тему и нашел этот (можно загрузить бесплатно). Подробнее см. http://www.albahari.com/threading/.

Я верю, что вы найдете то, что вам нужно для запуска выполнения в качестве нового потока на первых 20 страницах, и у него много других (не уверены в специфических фрагментах графического интерфейса, которые я подразумеваю строго для потоковой передачи). Был бы рад услышать, что сообщество думает об этой работе, потому что я читаю эту. На данный момент для меня это выглядит довольно аккуратно (для отображения специальных методов и типов .NET для потоковой передачи). Также он охватывает .NET 2.0 (а не древний 1.1), что я действительно ценю.

Ответ 14

Существует множество способов запуска отдельных потоков в .Net, каждый из которых имеет разные типы поведения. Вам нужно продолжить выполнение потока после завершения работы GUI? Вам нужно передавать информацию между потоком и графическим интерфейсом? Нужен ли поток для обновления графического интерфейса? Должен ли поток выполнить одну задачу, а затем выйти или продолжить работу? Ответы на эти вопросы расскажут вам, какой метод использовать.

На веб-сайте Code Project есть хорошая статья статья асинхронного метода, которая описывает различные методы и предоставляет пример кода.

Ответ 15

Я бы рекомендовал посмотреть на Jeff Richter Power Threading Library и, в частности, IAsyncEnumerator. Посмотрите видео на блог Чарли Калверта, где Рихтер просматривает его для хорошего обзора.

Не откладывайте имя, потому что он упрощает программирование задач асинхронного программирования.