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.