it-swarm.com.ru

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

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

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

314
Tim M

Хорошее место для начала чтения Джо Албахари .

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

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

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

Примечание:

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

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

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

Быстро и грязно, но сработает

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

using System.Threading;

простой код:

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

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

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

72
FallenAvatar

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

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

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

40
Andy

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

var someValue;

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

thread.Start();

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

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

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

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

6
Redbaron

Вот как можно использовать потоки с прогрессбаром, просто для понимания того, как работают потоки, в форме есть три прогрессбара и 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();
    }
}
4
Ammar Alyasry
// 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, поскольку большинство асинхронных реализаций выпускают дескриптор ожидания в EndInvoke.

3
Matt Davison

Если вы собираетесь использовать необработанный объект 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()
}

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

2
user50612

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

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

Обратите внимание, что эта статья была написана до того, как async/await шаблон и Task Parallel Library были введены в .NET.

1
Dour High Arch

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

при условии, что 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);
1
Charles Bretana

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

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

Искал .NET конкретную книгу по многопоточности и нашел этот (скачать бесплатно). Смотрите http://www.albahari.com/threading/ для получения более подробной информации об этом.

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

0
IgorK

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

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

0
Robert Paulson