ThreadStart с методом параметров - PullRequest
1 голос
/ 18 октября 2011

Я пытаюсь изучить Threading в .Net.

Многие из вас, должно быть, видели это:

private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(loop));
    t.Start();
}

private void loop()
{
    for (int i = 0; i < 100000; i++)
    {
        textBox1.Text = i.ToString();
    }
}

Работает нормально, но что если в моем методе цикла есть параметры, например:

private void loop(string str)
{
    for (int i = 0; i < 100000; i++)
    {
        textBox1.Text = i + str;
    }
}

Тогда как вызвать этот метод в моем ThreadStart, так как ThreadStart принимает только имя метода. Тогда как вызвать метод цикла в другом потоке?

Ответы [ 5 ]

2 голосов
/ 18 октября 2011
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Hello world");

private void loop(object obj)
{
    string str = (string)obj;

    for (int i = 0; i < 100000; i++)
    {
        // Don't do this: you can't change a control from another thread. Danger Will Robinson!
        textBox1.Text = i + str;
    }
}

Обратите внимание, что метод loop должен принимать параметр object, поэтому вам придется повысить object до вашего типа.Если вы не хотите, вы можете использовать закрытие и анонимный метод:

string str = "Hello world";
Thread t = new Thread(() => {
    for (int i = 0; i < 100000; i++)
    {
        // Don't do this: you can't change a control from another thread. Danger Will Robinson!   
        textBox1.Text = i + str;
    }
});
t.Start();

Таким образом, анонимный метод «закроется» вокруг str, и он будет похож как если бы вы передали параметр. Похоже потому что есть различия / проблемы с закрывающими переменными.На самом деле я написал бы что-то похожее на:

string str = "Hello world";

{
    string str2 = str;

    Thread t = new Thread(() => {
        for (int i = 0; i < 100000; i++)
        {
            // Don't do this: you can't change a control from another thread. Danger Will Robinson! 
            textBox1.Text = i + str2;
        }
    });

    t.Start();
}

, чтобы никто другой не мог «потрогать» str2.

Если вам нужно, я могу найти какой-нибудь ответ на SO, объясняющий это"проблема"

2 голосов
/ 18 октября 2011

Существует класс ParameterizedThreadStart, к которому можно привести делегаты с одним параметром при создании экземпляра потока:

private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(new ParameterizedThreadStart(loop));
    t.Start(str);
}

private void loop(string str)
{
    for (int i = 0; i < 100000; i++)
    {
        //the code you had is a no-no when you are multithreading;
        //all UI updates must occur on the main thread
        //textBox1.Text = i + str;
        UpdateTextBoxText(textBox1, i+str);
    }
}

private void UpdateTextBoxText(TextBox textBox, string text)
{
   //the method will invoke itself on the main thread if it isn't already running there
   if(InvokeRequired)
   {
      this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(TextBox textBox, string text)));
      return;
   }

   textBox.Text = text;
}

Если вам не требуется очень детальное управление при запуске и остановке потокавы можете оставить его в ThreadPool и использовать Delegate.BeginInvoke:

private void button1_Click(object sender, EventArgs e)
{
    Action<string> method = loop;

    method.BeginInvoke(str, null, null);
}

private void loop(string str)
{
    for (int i = 0; i < 100000; i++)
    {
        //textBox1.Text = i + str;
        UpdateTextBoxText(textBox1, i+str);
    }
}

private void UpdateTextBoxText(TextBox textBox, string text)
{
   //the method will invoke itself on the main thread if it isn't already running there
   if(InvokeRequired)
   {
      this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(textBox, text)));
      return;
   }

   textBox.Text = text;
}
2 голосов
/ 18 октября 2011

Вместо этого вы использовали бы ParameterizedThreadStart: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx

Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Foo");

// Note the use of Object here to match the delegate signature
private void loop(Object state)
{
    var str = state as String;
    for (int i = 0; i < 100000; i++)
    {
        // For what it is worth, this is illegal:
        // textBox1.Text = i + str;
        // You need to Invoke back to the UI thread to access a control's properties:
        textBox1.Invoke(()=> { textBox1.Text = i + str; });
    }
}
1 голос
/ 18 октября 2011

Взгляните на ParameterizedThreadStart , он позволяет передавать параметры в функцию запуска потока.

0 голосов
/ 18 октября 2011

Как это:

new Thread(() => loop("MyString")).Start();

Вам даже не нужно связываться с ThreadStart / ParameterizedThreadStart.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...