NET দিয়ে থ্রেড শেষ হওয়ার জন্য কীভাবে অপেক্ষা করবেন?


178

আমি সত্যিই সি # তে আগে কখনও থ্রেডিং ব্যবহার করি নি যেখানে আমার দুটি থ্রেড, পাশাপাশি মূল ইউআই থ্রেড থাকা দরকার। মূলত, আমি নিম্নলিখিত আছে।

public void StartTheActions()
{
  //Starting thread 1....
  Thread t1 = new Thread(new ThreadStart(action1));
  t1.Start();

  // Now, I want for the main thread (which is calling `StartTheActions` method) 
  // to wait for `t1` to finish. I've created an event in `action1` for this. 
  // The I wish `t2` to start...

  Thread t2 = new Thread(new ThreadStart(action2));
  t2.Start();
}

সুতরাং, মূলত, আমার প্রশ্নটি হল যে কীভাবে একটি থ্রেড অপরটির সমাপ্তির জন্য অপেক্ষা করবেন। এই কাজ করতে সবচেয়ে ভালো উপায় কি?


4
যদি আপনি "... এর আগে কখনও থ্রেডিং ব্যবহার করেন নি ..." আপনি কিছু সহজ বিকল্প যেমন * অ্যাসিঙ্ক () প্যাটার্ন বিবেচনা করতে পারেন।
Ðаn

4
আপনি যদি যাইহোক যাইহোক থ্রেড 1 এর সমাপ্তির অপেক্ষায় থাকেন তবে আপনি কেন কেবল সেই পদ্ধতিটিকে সিঙ্ক্রোনালি কল করছেন না?
Svish

13
আপনি যখন লিনিয়ার ফ্যাশনে প্রসেস করছেন তখন থ্রেডগুলি ব্যবহার করার কী দরকার?
জন

1
@ জন, এটি আমার কাছে মোটামুটি বোঝায় যে ব্যবহারকারী কাজ করার সময় একটি পটভূমি থ্রেড কাটানোর জন্য অনেকগুলি ব্যবহার রয়েছে। এছাড়াও, আপনার প্রশ্নটি আগেরটির মতো নয়?
ব্যবহারকারী 34660

সহজ ব্যবহারের জন্য ব্যাকগ্রাউন্ড ওয়ার্কার ব্যবহার করে রোটমের উত্তর , এটি খুব সহজ।
কামিল

উত্তর:


264

আমি উপলব্ধ 5 টি বিকল্প দেখতে পাচ্ছি:

1. থ্রেড.জয়াইন

যেমনটি মিচের উত্তরের সাথে। তবে এটি আপনার ইউআই থ্রেডকে ব্লক করবে, তবে আপনি আপনার জন্য একটি টাইমআউট তৈরি করেছেন।


2. ব্যবহার ক WaitHandle

ManualResetEventযেমন একটি WaitHandleজ্রিস্টা প্রস্তাবিত।

একটি বিষয় লক্ষণীয় হ'ল আপনি যদি একাধিক থ্রেডের জন্য অপেক্ষা করতে চান তবে WaitHandle.WaitAll()এটি ডিফল্টরূপে কাজ করবে না, কারণ এটির জন্য এমটিএ থ্রেড প্রয়োজন। আপনি আপনার Main()পদ্ধতিটি চিহ্নিত করে এটিকে ঘিরে ফেলতে পারেন MTAThread- তবে এটি আপনার বার্তা পাম্পটিকে অবরুদ্ধ করে এবং আমি যা পড়েছি তা থেকে সুপারিশ করা হয় না।


3. একটি ইভেন্ট ফায়ার

ইভেন্ট এবং মাল্টি-থ্রেডিং সম্পর্কে জন স্কিটির এই পৃষ্ঠাটি দেখুন , এটি সম্ভবত যে কোনও ইভেন্ট ifএবং এর মধ্যে সদস্যতা ছাড়াই যেতে পারেEventName(this,EventArgs.Empty) আমার - এটি আমার আগে ঘটেছিল।

(আশা করি এই সংকলন, আমি চেষ্টা করিনি)

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();
        worker.ThreadDone += HandleThreadDone;

        Thread thread1 = new Thread(worker.Run);
        thread1.Start();

        _count = 1;
    }

    void HandleThreadDone(object sender, EventArgs e)
    {
        // You should get the idea this is just an example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;

            Thread thread2 = new Thread(worker.Run);
            thread2.Start();

            _count++;
        }
    }

    class ThreadWorker
    {
        public event EventHandler ThreadDone;

        public void Run()
        {
            // Do a task

            if (ThreadDone != null)
                ThreadDone(this, EventArgs.Empty);
        }
    }
}

4. একটি প্রতিনিধি ব্যবহার করুন

public class Form1 : Form
{
    int _count;

    void ButtonClick(object sender, EventArgs e)
    {
        ThreadWorker worker = new ThreadWorker();

        Thread thread1 = new Thread(worker.Run);
        thread1.Start(HandleThreadDone);

        _count = 1;
    }

    void HandleThreadDone()
    {
        // As before - just a simple example
        if (_count == 1)
        {
            ThreadWorker worker = new ThreadWorker();

            Thread thread2 = new Thread(worker.Run);
            thread2.Start(HandleThreadDone);

            _count++;
        }
    }

    class ThreadWorker
    {
        // Switch to your favourite Action<T> or Func<T>
        public void Run(object state)
        {
            // Do a task

            Action completeAction = (Action)state;
            completeAction.Invoke();
        }
    }
}

আপনি যদি _ অ্যাকাউন্ট পদ্ধতিটি ব্যবহার করেন তবে এটি ব্যবহার করে বাড়িয়ে নেওয়া কোনও ধারণা (নিরাপদ থাকতে) হতে পারে

Interlocked.Increment(ref _count)

আমি থ্রেড নোটিফিকেশনের জন্য প্রতিনিধি এবং ইভেন্টগুলির মধ্যে পার্থক্যটি জানতে আগ্রহী হব, ইভেন্টগুলির মধ্যে কেবলমাত্র পার্থক্যটিই আমি সিঙ্ক্রোনালি বলা হয়।


৫. পরিবর্তে এটি অবিচ্ছিন্নভাবে করুন

উত্তর এই প্রশ্ন এই পদ্ধতি সঙ্গে আপনার বিকল্প একটি খুব পরিষ্কার বিবরণ নেই।


প্রতিনিধি / ইভেন্টের ভুল থ্রেড

ইভেন্টগুলি করার / ইভেন্টের প্রতিনিধি হওয়ার অর্থ হ'ল আপনার ইভেন্ট হ্যান্ডলার পদ্ধতিটি মূল UI থ্রেড নয় থ্রেড 1 / থ্রেড 2 এ রয়েছে , সুতরাং আপনাকে হ্যান্ডলথ্রেডডোন পদ্ধতিগুলির শীর্ষে ফিরে যেতে হবে:

// Delegate example
if (InvokeRequired)
{
    Invoke(new Action(HandleThreadDone));
    return;
}

61

যোগ

t1.Join();    // Wait until thread t1 finishes

আপনি এটি শুরু করার পরে, তবে এটি মূল থ্রেডে চলার মতো একই ফলাফলটি অত্যাবশ্যক হিসাবে এটি এতটা অর্জন করতে পারে না!

আপনি নেট। এনডিতে থ্রেডিংয়ের উপলব্ধি অর্জন করতে চাইলে আমি সি # ফ্রি ই-বইতে জো আলবাহারির থ্রেডিংটি পড়ার জন্য আমি উচ্চ প্রস্তাব দিয়েছি ।


4
যদিও Joinআক্ষরিক অর্থে প্রশ্নকর্তা যা চেয়েছিলেন তা মনে হলেও সাধারণভাবে এটি অত্যন্ত খারাপ হতে পারে। একটি কল Joinথ্রেড হ্যাং করবে যা থেকে এটি করা হচ্ছে। যদি এটির মূল জিইউআই থ্রেড হয়, তবে এটি বিএডি ! একজন ব্যবহারকারী হিসাবে আমি সক্রিয়ভাবে এমন অ্যাপ্লিকেশনগুলিকে ঘৃণা করি যেগুলি এইভাবে কাজ করে। তাই এই প্রশ্ন ও সব অন্যান্য উত্তরগুলি দেখতে দয়া করে stackoverflow.com/questions/1221374/...
peSHIr

1
আমি সম্মত হই যে সাধারণভাবে যোগদান () খারাপ। আমি সম্ভবত আমার উত্তরে এটি যথেষ্ট স্পষ্ট করে তুলিনি।
মিচ গম

2
বলছি, একটি আকার সব মাপসই করা হয় না । এমন পরিস্থিতি রয়েছে, যখন একজনকে সত্যই নিশ্চিত হওয়া দরকার, সেই থ্রেডটি তার কাজ শেষ করেছে: বিবেচনা করুন, থ্রেডটি ডেটা প্রসেস করে, যা প্রায় পরিবর্তন হতে চলেছে। সেক্ষেত্রে থ্রেডকে কৃপণভাবে বাতিল করার জন্য অবহিত করা এবং এটি শেষ না হওয়া পর্যন্ত অপেক্ষা করা (বিশেষত, যখন এক ধাপ খুব দ্রুত প্রক্রিয়া করা হয়) আইএমও পুরোপুরি ন্যায়সঙ্গত। আমি বরং বলতে চাই, যে যোগদান খারাপ (সি ++ এফএকিউ শর্তাবলী), মানে। এটি সত্যই প্রয়োজন না হলে ব্যবহৃত হবে না ।
ভূত

5
আমি স্পষ্টভাবে বলতে চাই, জয়েন একটি হাতিয়ার, এটি কার্যকর হতে পারে, তবুও এটি প্রায়শই অপব্যবহার করা হয়। কিছু পরিস্থিতি রয়েছে, যখন এটি কোনও অযৌক্তিক পার্শ্ব প্রতিক্রিয়া ছাড়াই কাজ করবে (যেমন উল্লেখযোগ্য সময়ের জন্য মূল জিইউআই থ্রেড স্টলিং)।
ভূত

2
যোগদান একটি সরঞ্জাম? আমি মনে করি আপনি এটি একটি পদ্ধতি খুঁজে পাবেন।
মিচ গম

32

পূর্ববর্তী দুটি উত্তর দুর্দান্ত, এবং সাধারণ দৃশ্যের জন্য কাজ করবে। তবে থ্রেডগুলি সিঙ্ক্রোনাইজ করার অন্যান্য উপায় রয়েছে। নিম্নলিখিতগুলিও কাজ করবে:

public void StartTheActions()
{
    ManualResetEvent syncEvent = new ManualResetEvent(false);

    Thread t1 = new Thread(
        () =>
        {
            // Do some work...
            syncEvent.Set();
        }
    );
    t1.Start();

    Thread t2 = new Thread(
        () =>
        {
            syncEvent.WaitOne();

            // Do some work...
        }
    );
    t2.Start();
}

.NET ফ্রেমওয়ার্কটি যে বিভিন্ন ওয়েটহ্যান্ডলকে সরবরাহ করতে পারে তার মধ্যে একটি ম্যানুয়ালসেটভেন্ট । এগুলি লক () / মনিটর, থ্রেড.জয়িন ইত্যাদির মতো সাধারণ তবে খুব সাধারণ সরঞ্জামগুলির চেয়ে অনেক বেশি সমৃদ্ধ থ্রেড সিঙ্ক্রোনাইজেশন ক্ষমতা সরবরাহ করতে পারে They যা একাধিক 'শিশু' থ্রেডগুলি সমন্বিত করে, একাধিক সমবর্তী প্রক্রিয়াগুলি যা একে অপরের বেশ কয়েকটি পর্যায়ে সিঙ্ক্রোনাইজ হওয়ার জন্য নির্ভর করে ইত্যাদি coord


29

.NET 4 থেকে ব্যবহার করা হলে এই নমুনা আপনাকে সহায়তা করতে পারে:

class Program
{
    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => doStuff());
        Task task2 = Task.Factory.StartNew(() => doStuff());
        Task task3 = Task.Factory.StartNew(() => doStuff());
        Task.WaitAll(task1, task2, task3);
        Console.WriteLine("All threads complete");
    }

    static void doStuff()
    {
        //do stuff here
    }
}

থেকে: https://stackoverflow.com/a/4190969/1676736


8
আপনি নিজের উত্তরে থ্রেডস সম্পর্কে কিছু উল্লেখ করেন নি। প্রশ্নটি থ্রেডস সম্পর্কিত, টাস্কগুলির বিষয়ে নয়। দুটি একই নয়।
সুমায়ার

7
আমি আসল পোস্টারে একটি অনুরূপ প্রশ্ন (এবং জ্ঞানের স্তর) নিয়ে এসেছি এবং এই উত্তরটি আমার কাছে অত্যন্ত মূল্যবান ছিল - আমি যা করছি তার জন্য কার্যগুলি আরও উপযুক্ত এবং যদি আমি এই উত্তরটি না খুঁজে পাই তবে আমি আমার নিজের ভয়ানক থ্রেড পুল
ক্রিস রায়ে

1
@ ক্রিসআরএ, সুতরাং এটি মূল প্রশ্নের একটি মন্তব্য হওয়া উচিত, এটির মতো উত্তর নয়।
জাইমে হাবলুটজেল

এই নির্দিষ্ট উত্তরটি সম্পর্কে এটি আমার মনে হয় এটি সম্ভবত এখানে আরও বোধগম্য হয়।
ক্রিস রাই

1
যেমন @ সুমের বলেছেন, এই উত্তরটি সম্পূর্ণরূপে ওপি প্রশ্নের সাথে সম্পর্কিত নয়।
গ্লেন স্লেডেন


4

আমি আপনার মূল থ্রেডটিকে আপনার প্রথম থ্রেডে কলব্যাক পদ্ধতিটি পাস করতে দেব এবং এটি শেষ হয়ে গেলে এটি মূল থ্রেডে কলব্যাক পদ্ধতিটি শুরু করবে, যা দ্বিতীয় থ্রেড চালু করতে পারে। এটি আপনার মূল থ্রেডটিকে কোনও যোগদান বা ওয়েথ্যান্ডলের অপেক্ষা করার সময় ঝুলন্ত থেকে রক্ষা করে। প্রতিনিধি হিসাবে পাস করার পদ্ধতিগুলি যেভাবেই সি # এর সাথে শেখার জন্য একটি দরকারী জিনিস।



0

কিছু অন্যকে সহায়তার জন্য পোস্ট করা, আমি কীভাবে এসেছি এর মতো সমাধান খুঁজতে বেশ কিছুটা সময় ব্যয় করলাম। তাই আমি কিছুটা ভিন্ন পন্থা নিয়েছি। উপরে একটি পাল্টা বিকল্প রয়েছে, আমি এটি কিছুটা আলাদাভাবে প্রয়োগ করেছি। আমি অসংখ্য থ্রেড কাটছিলাম এবং একটি কাউন্টার বাড়িয়েছিলাম এবং থ্রেড শুরু হওয়ার সাথে সাথে একটি কাউন্টারকে হ্রাস পেয়েছি। তারপরে মূল পদ্ধতিতে আমি বিরতি দিতে এবং থ্রেডগুলি সম্পন্ন করার জন্য অপেক্ষা করতে চাইছিলাম।

while (threadCounter > 0)
{
    Thread.Sleep(500); //Make it pause for half second so that we don’t spin the cpu out of control.
}

আমার ব্লগে নথিভুক্ত http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/


4
একে ব্যস্ত ওয়েটিং বলে। হ্যাঁ এটি কাজ করে এবং কখনও কখনও সর্বোত্তম সমাধান, তবে আপনি যদি সম্ভব হয় তবে এড়াতে চান কারণ এটি
সিপিইউয়ের

@ মোটরমন এটি একটি নিয়মের চেয়ে আরও বেশি গাইডলাইন। এই ক্ষেত্রে যেহেতু সেই লুপটি সিপিইউর 0.00000001% নষ্ট করতে পারে এবং ওপেন সি # তে কোডিং করছে, এটিকে 'আরও দক্ষ' এর সাথে প্রতিস্থাপন করা সময়ের অপচয় হবে। অপ্টিমাইজেশনের প্রথম নিয়মটি হ'ল - না। প্রথমে পরিমাপ করুন।
স্পাইক0xff

0

যখন আমি চাই যে কোনও কাজ শেষ হওয়ার অপেক্ষায় ইউআই এর প্রদর্শনটি আপডেট করতে সক্ষম হয়, আমি থ্রেডে আইসালাইভ পরীক্ষা করে এমন একটি লুপ ব্যবহার করি:

    Thread t = new Thread(() => someMethod(parameters));
    t.Start();
    while (t.IsAlive)
    {
        Thread.Sleep(500);
        Application.DoEvents();
    }

-1

এখানে একটি সাধারণ উদাহরণ যা একই ক্লাসের মধ্যে চলার জন্য অপেক্ষা করে। এটি একই নেমস্পেসে অন্য শ্রেণিতে কল করে। আমি "ব্যবহার করে" বিবৃতিগুলি অন্তর্ভুক্ত করেছি যাতে এটি উইনফর্ম হিসাবে কার্যকর করা যায় যতক্ষণ আপনি বোতাম 1 তৈরি করবেন।

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace ClassCrossCall
{

 public partial class Form1 : Form
 {
  int number = 0; // this is an intentional problem, included for demonstration purposes
  public Form1()
  {
   InitializeComponent();
  }
  private void Form1_Load(object sender, EventArgs e)
  {
   button1.Text="Initialized";
  }
  private void button1_Click(object sender, EventArgs e)
  {
   button1.Text="Clicked";
   button1.Refresh();
   Thread.Sleep(400);
   List<Task> taskList = new List<Task>();
   taskList.Add(Task.Factory.StartNew(() => update_thread(2000)));
   taskList.Add(Task.Factory.StartNew(() => update_thread(4000)));
   Task.WaitAll(taskList.ToArray());
   worker.update_button(this,number);
  }
  public void update_thread(int ms)
  {
   // It's important to check the scope of all variables
   number=ms; // this could be either 2000 or 4000.  Race condition.
   Thread.Sleep(ms);
  }
 }

 class worker
 {
  public static void update_button(Form1 form, int number)
  {
   form.button1.Text=$"{number}";
  }
 }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.