ThreadStart з параметрами


261

Як запустити потік з параметрами в C #?


Відповідь на це запитання сильно різниться у різних версіях часу виконання - це 3,5 відповіді?
quillbreaker

4
Ого. Я редагував деякі ваші старі питання, але це може бути робота на повний робочий день. Я забув, ну, наскільки ти покращився за ці роки. :-)
Джон Сондерс

Якби я задав таке коротке запитання, я отримав би 5 негативних балів або навіть більше! Хоча питання і відповідь мені допомогли.
Мухаммед Мусаві

Відповіді:


174

Так:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);

14
це те саме: ThreadStart processTaskThread = делегат {ProcessTasks (databox.DataboxID); }; нова тема (processTaskThread) .Start ();
JL.

43
Що таке myParamObject та myUrl?
dialex

3
У цьому випадку void MyParamObject(object myUrl){ //do stuff }повинен бути тип параметраobject
Ельшан

15
-1 оскільки відповідь передбачає, що ОП знає, як це використовувати, ParameterizedThreadStartі чітко з тексту запитання, це, мабуть, не так.
JYelton

2
У мене ця помилка Помилка CS0123 Немає перевантаження для делегата "UpdateDB" матчів "ParameterizedThreadStart"
Omid Farvid

482

Одне з 2 перевантажень конструктора Thread використовує делегат ParameterizedThreadStart, який дозволяє передавати один параметр методу запуску. На жаль, він допускає лише один параметр і робить це небезпечно, оскільки передає його як об'єкт. Мені здається, що набагато простіше використовувати лямбда-вираз для збору відповідних параметрів та передачі їх у сильно набраному вигляді.

Спробуйте наступне

public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
  var t = new Thread(() => RealStart(param1, param2));
  t.Start();
  return t;
}

private static void RealStart(SomeType param1, SomeOtherType param2) {
  ...
}

41
+1: Незважаючи на те, що обрана на даний момент відповідь абсолютно правильна, ця відповідь JaredPar є кращою. Це просто найкраще рішення для більшості практичних випадків.
галактор

2
Це рішення набагато краще, ніж стандартний ParameterizedThreadStart
Piotr Owsiak

5
Приємно так просто. Просто загорніть будь-який дзвінок у "нову тему (() => FooBar ()) .Start ();
Thomas Jespersen

12
Дивовижно, це для хлопців VB.NETDim thr As New Thread(Sub() DoStuff(settings))
д-р. зло

3
@bavaza Я тільки мав на увазі перевірку статичного типу
JaredPar

141

Можна використовувати лямбда-вирази

private void MyMethod(string param1,int param2)
{
  //do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();

це поки що найкраща відповідь, яку я міг знайти, це швидко і легко.


6
Найкраще рішення для простих випадків ІМО
Данк

1
що це =>? і де я можу знайти більше інформації про синтаксис?
Нік

2
Це лямбда-вираз, деяку інформацію можна знайти за цими адресами: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
Це працювало для мене. Я спробував ParameterizedThreadStart та його варіанти, але не мав радості. Я використовував .NET Framework 4 в нібито простому консольному додатку.
Даніель Холлінрак

Це найкраще підходить для людей, які звикли до такого роду делегатів. Початківцям це може бути складно. Це, однак, відповідає стандартам C #. Прийнята відповідь не працює для мене, і я не маю часу з’ясувати, чому.
Bitterblue

37
Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param)
{
    string Parameter = (string)param;
}

Тип параметра повинен бути об'єктом.

Редагувати:

Хоча ця відповідь є невірною, я не рекомендую проти такого підходу. Використовувати лямбда-вираз набагато простіше для читання і не вимагає кастингу типу. Дивіться тут: https://stackoverflow.com/a/1195915/52551


Чому ви допомагаєте з кодом, який не компілюється;) Parameter?
Себастьян Ксавері Wiśniowiecki

32
class Program
{
    static void Main(string[] args)
    {
        Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));

        t.Start("My Parameter");
    }

    static void ThreadMethod(object parameter)
    {
        // parameter equals to "My Parameter"
    }
}

3
Це дає мені "Без перевантаження для делегата" DoWork "матчів" System.Threading.ParameterizedThreadStart "
anon58192932

1
Яка буде різниця, якщо ви щойно передали ThreadMethod під час ініціалізації теми?
Джо

Пам'ятайте, тип параметра повинен бути типу "Object"
Kunal Uppal

28

Простий спосіб використання лямбда, як так ..

Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();

АБО ти навіть можеш так delegateвикористовувати ThreadStart...

ThreadStart ts = delegate
{
     bool moreWork = DoWork("param1", "param2", "param3");
     if (moreWork) 
     {
          DoMoreWork("param4", "param5");
     }
};
new Thread(ts).Start();

АБО використовуйте VS 2019 .NET 4.5+ навіть більш чистий, як так ..

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}



6

Як уже згадувалося в різних відповідях тут, Threadклас в даний час (4.7.2) надає кілька конструкторів і Startметод з перевантаженнями.

Ці відповідні конструктори для цього питання:

public Thread(ThreadStart start);

і

public Thread(ParameterizedThreadStart start);

які або приймають ThreadStartделегата, або ParameterizedThreadStartделегата.

Відповідні делегати виглядають так:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

Отже, як видно, правильний конструктор для використання, здається, є тим, хто приймає ParameterizedThreadStartделегата, так що якийсь метод, відповідний вказаній підписі делегата, може бути запущений потоком.

Простий приклад для інстанціювання Threadкласу

Thread thread = new Thread(new ParameterizedThreadStart(Work));

або просто

Thread thread = new Thread(Work);

Підпис відповідного методу (називається Workв цьому прикладі) виглядає так:

private void Work(object data)
{
   ...
}

Залишилося запустити нитку. Це робиться за допомогою будь-якого

public void Start();

або

public void Start(object parameter);

Хоча Start()запускається потік і передається nullяк дані методу, Start(...)може використовуватися для передачі чого-небудь в Workметод потоку.

Однак у цьому підході є одна велика проблема: все, що передається Workметоду, передається об'єкту. Це означає, що в рамках Workметоду його потрібно передати оригінальному типу знову, як у наступному прикладі:

public static void Main(string[] args)
{
    Thread thread = new Thread(Work);

    thread.Start("I've got some text");
    Console.ReadLine();
}

private static void Work(object data)
{
    string message = (string)data; // Wow, this is ugly

    Console.WriteLine($"I, the thread write: {message}");
}



Кастинг - це те, чого ти зазвичай не хочеш робити.

Що робити, якщо хтось передає щось інше, що не є рядком? Оскільки це здається неможливим спочатку (оскільки це мій метод, я знаю, що я роблю, або метод є приватним, як хто-небудь коли-небудь зможе передати йому що-небудь? ), Можливо, у вас може виникнути саме такий випадок з різних причин . Оскільки деякі випадки можуть не бути проблемою, інші є. У таких випадках ви, ймовірно, закінчитесь з тим, InvalidCastExceptionчого ви, ймовірно, не помітите, оскільки воно просто завершує нитку.

Як рішення, ви б очікували отримати загальний ParameterizedThreadStartделегат, наприклад, ParameterizedThreadStart<T>де Tбуде тип даних, який ви хочете передати в Workметод. На жаль, щось подібне не існує (поки що?).

Однак існує вирішення цього питання. Він включає створення класу, який містить обидва, дані, що передаються в потік, а також метод, який представляє такий собі робочий метод:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

При такому підході ви б почали нитку так:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

Тож таким чином ви просто уникаєте закидання та маєте безпечний спосіб надання даних у потік ;-)


Нічого собі, голос без коментарів ... Або моя відповідь така погана, як акторський склад, або читач не зрозумів, що я тут намагався вказати ;-)
Маркус Сафар

1
Я знайшов ваше рішення дуже легким, вітаю. Просто хотів додати, що я вже пройшов тестування в Net.Core наступне і працював, не маючи чіткості кидати! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Пол Еффорд

@PaulEfford Спасибі ;-) Ваше рішення здається приємним. Але ви не отримуєте доступу до певної інформації, оскільки вона все одно буде розміщена в об'єкті, правда? (наприклад, message.Lengthце неможливо тощо)
Маркус Сафар

1
вірно ... ви можете message.GetType () і передавати, якщо вимагається якесь конкретне властивість, наприклад if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. У всякому разі, замість того , щоб використовувати свій метод потокової я знайшов трохи більш зручним у використанні Tasks<T>, як, наприклад tasks.Add(Task.Run(() => Calculate(par1, par2, par3))), побачити моя відповідь нижче ( stackoverflow.com/a/59777250/7586301 )
Пол Еффорд

5

У мене виникла проблема у переданому параметрі. Я передав ціле число від циклу for для функції та відображав його, але воно завжди давало різні результати. наприклад (1,2,2,3) (1,2,3,3) (1,1,2,3) тощо з делегатом ParametrizedThreadStart .

цей простий код працював як шарм

Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param) 
{
 string Parameter = (string)param; 
}

4

ParameterizedThreadStartПриймає один параметр. Ви можете використовувати це для надсилання одного параметра або спеціального класу, що містить декілька властивостей.

Інший метод полягає в тому, щоб поставити метод, який ви хочете запустити як член екземпляра в класі, разом із властивостями параметрів, які ви хочете встановити. Створіть екземпляр класу, встановіть властивості та запустіть потік із зазначенням екземпляра та методу, і метод може отримати доступ до властивостей.


3

Ви можете використовувати делегат ParametrizedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);


1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.IsBackground = true;//i can stope 
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


                for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }`enter code here`
    }
}

0

Я пропоную використовувати Task<T>замість Thread; це дозволяє кілька параметрів і виконує дійсно чудово.

Ось робочий приклад:

    public static void Main()
    {
        List<Task> tasks = new List<Task>();

        Console.WriteLine("Awaiting threads to finished...");

        string par1 = "foo";
        string par2 = "boo";
        int par3 = 3;

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => Calculate(par1, par2, par3))); 
        }

        Task.WaitAll(tasks.ToArray());

        Console.WriteLine("All threads finished!");
    }

    static bool Calculate1(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }

    // if need to lock, use this:
    private static Object _locker = new Object();"

    static bool Calculate2(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }

-2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


            for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }
    }
}

Багатопотокове нарізування C # Нитками дозволяє розробити ефективніші програми, що синхронізуються через спільну пам'ять.
Мохаммед Хассен Ісмаїле
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.