আমি কীভাবে টিপিএল কার্য বাতিল / বাতিল করব?


156

একটি থ্রেডে, আমি কিছু তৈরি করে System.Threading.Taskপ্রতিটি কাজ শুরু করি ।

আমি যখন .Abort()থ্রেডটি মেরে ফেলতে পারি , তখন কার্যগুলি বাতিল করা হয় না।

আমি কীভাবে .Abort()আমার কাজগুলিতে প্রেরণ করতে পারি ?


উত্তর:


228

আপনি পারবেন না। টাস্কগুলি থ্রেড পুল থেকে পটভূমি থ্রেড ব্যবহার করে। অ্যাওর্ট পদ্ধতি ব্যবহার করে থ্রেড বাতিল করারও প্রস্তাব দেওয়া হয় না। আপনি নিম্নলিখিত ব্লগ পোস্টটি একবার দেখে নিতে পারেন যা বাতিলকরণ টোকেনগুলি ব্যবহার করে কার্য বাতিল করার উপযুক্ত পদ্ধতি সম্পর্কে ব্যাখ্যা করে। এখানে একটি উদাহরণ:

class Program
{
    static void Main()
    {
        var ts = new CancellationTokenSource();
        CancellationToken ct = ts.Token;
        Task.Factory.StartNew(() =>
        {
            while (true)
            {
                // do some heavy work here
                Thread.Sleep(100);
                if (ct.IsCancellationRequested)
                {
                    // another thread decided to cancel
                    Console.WriteLine("task canceled");
                    break;
                }
            }
        }, ct);

        // Simulate waiting 3s for the task to complete
        Thread.Sleep(3000);

        // Can't wait anymore => cancel this task 
        ts.Cancel();
        Console.ReadLine();
    }
}

5
সুন্দর ব্যাখ্যা। আমার একটি প্রশ্ন আছে, যখন আমাদের কাছে টাস্ক.ফ্যাক্টরি.স্টার্টনিউতে কোনও বেনামি পদ্ধতি নেই তখন এটি কীভাবে কাজ করবে? যেমন টাস্ক.ফ্যাক্টরি.স্টার্টনিউ (() => প্রসেসমাইথোথ (), বাতিলকরণ
টোকেন

61
যদি কোনও ব্লকিং কল থাকে যা কার্যকরকারী কার্যের মধ্যে ফিরে না আসে?
mehmet6parmak

3
@ মেহমেট p পারমাক আমার মনে হয় আপনি কেবল তখনই করতে পারেন Task.Wait(TimeSpan / int)এটি বাইরে থেকে একটি (সময় ভিত্তিক) সময়সীমা দেওয়ার জন্য ব্যবহার করা।
চিহ্নিত করুন

2
আমি যদি আমার কাস্টম ক্লাসটি একটি নতুন অভ্যন্তরে পদ্ধতির সম্পাদন পরিচালনা করতে Taskপারি? ভালো কিছু: public int StartNewTask(Action method)। ইনসাইড StartNewTaskপদ্ধতি আমি একটি নতুন তৈরি Taskকরুন: Task task = new Task(() => method()); task.Start();। সুতরাং আমি কিভাবে পরিচালনা করতে পারি CancellationToken? আমিও মতো যদি জানেন যে হবে Threadআমি যদি সেখানে কিছু কাজ এখনও Hangout এ আছেন করছি পরীক্ষা করার যুক্তিবিজ্ঞান বাস্তবায়ন এবং তাই যখন তাদের হত্যা প্রয়োজন Form.Closing। সঙ্গে Threadsআমি ব্যবহার Thread.Abort()
চশায়ার বিড়াল

ওম, কী খারাপ উদাহরণ! এটি একটি সাধারণ বুলিয়ান অবস্থা, অবশ্যই এটিই প্রথম চেষ্টা করবে! তবে অর্থ্যাৎ আমার একটি পৃথক টাস্কে একটি ফাংশন রয়েছে যা শেষ হতে অনেক বেশি সময় নিতে পারে এবং আদর্শভাবে এটি কোনও থ্রেডিং বা যা কিছু সম্পর্কে কিছুই জেনে রাখা উচিত নয়। তাহলে আমি কীভাবে আপনার পরামর্শ দিয়ে ফাংশনটি বাতিল করব?
হাই-এঞ্জেল

32

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

void Main()
{
    Thread thread = null;

    Task t = Task.Run(() => 
    {
        //Capture the thread
        thread = Thread.CurrentThread;

        //Simulate work (usually from 3rd party code)
        Thread.Sleep(1000);

        //If you comment out thread.Abort(), then this will be displayed
        Console.WriteLine("Task finished!");
    });

    //This is needed in the example to avoid thread being still NULL
    Thread.Sleep(10);

    //Cancel the task by aborting the thread
    thread.Abort();
}

আমি এর জন্য সর্বাধিক সাধারণ ব্যবহারের কেসটি দেখানোর জন্য টাস্ক.আরুন () ব্যবহার করেছি - পুরানো একক থ্রেডযুক্ত কোড সহ টাস্কের সান্ত্বনা ব্যবহার করে, যা বাতিল করা উচিত কিনা তা নির্ধারণের জন্য বাতিলকরণ টোকেনসোর্স শ্রেণি ব্যবহার করে না।


2
এই ধারণার জন্য ধন্যবাদ। কিছু বাহ্যিক কোডের সময়সীমা বাস্তবায়নের জন্য এই পদ্ধতির ব্যবহার করা হয়েছে, যার কোনও CancellationTokenসমর্থন নেই ...
ক্রিস্টোফ ফিঙ্ক

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

1
আমি যেমন লিখেছি - এই সমাধানটি একটি শেষ অবলম্বন যা নির্দিষ্ট পরিস্থিতিতে বিবেচনা করা যেতে পারে। অবশ্যই একটি CancellationTokenবা এমনকি সহজ সমাধান যা জাতি-শর্ত মুক্ত বিনামূল্যে বিবেচনা করা উচিত। উপরের কোডটি কেবল ব্যবহারের ক্ষেত্র নয়, পদ্ধতিটি চিত্রিত করে।
ফ্লোরিয়ান র্যাপল

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

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

32

ভালো লেগেছে এই পোস্ট প্রস্তাব দেওয়া, এই নিম্নলিখিত পদ্ধতিতে করা সম্ভব:

int Foo(CancellationToken token)
{
    Thread t = Thread.CurrentThread;
    using (token.Register(t.Abort))
    {
        // compute-bound work here
    }
}

যদিও এটি কাজ করে, এ জাতীয় পদ্ধতির ব্যবহার করার পরামর্শ দেওয়া হয় না। যদি আপনি কার্য সম্পাদন করে এমন কোডটি নিয়ন্ত্রণ করতে পারেন তবে আপনি বাতিল করার সঠিক পরিচালনা সহ আরও ভাল d


6
ফলব্যাকগুলি উল্লেখ করার সময় একটি ভিন্ন পদ্ধতির জন্য +1। আমি জানতাম না এটি করা যেতে পারে :)
জোয়েল

1
সমাধানের জন্য ধন্যবাদ! আমরা কেবল কোনও পদ্ধতিতে থ্রেড উদাহরণ পেতে এবং সরাসরি এই উদাহরণটি বাতিল করতে পরিবর্তে, কেবল টোকন পদ্ধতিতে টোকেন উত্সাহ এবং বাতিল করতে পারি।
স্যাম

কার্যটির থ্রেড যা বাতিল হয়ে যায় তা থ্রেড-পুল থ্রেড বা কলকারীকে ডেকে আনা থ্রেডের থ্রেড হতে পারে। এটি এড়ানোর জন্য, আপনি কার্যের জন্য একটি উত্সর্গীকৃত থ্রেড নির্দিষ্ট করতে একটি টাস্কশেডুলার ব্যবহার করতে পারেন
এডওয়ার্ড ব্রে

19

এই ধরণের জিনিস হ্রাস করা হয় কেন Abortএকটি যৌক্তিক কারণ । প্রথম এবং সর্বাগ্রে, যদি সম্ভব হয় তবে কোনও থ্রেড বাতিল বা বন্ধ করতে ব্যবহার করবেন না Thread.Abort() Abort()সময় মতো ফ্যাশনে থামার জন্য আরও শান্তিপূর্ণ অনুরোধগুলির প্রতিক্রিয়া না করে এমন এক থ্রেডকে জোরতার সাথে হত্যা করতে ব্যবহার করা উচিত।

বলা হচ্ছে, আপনাকে একটি ভাগ করা বাতিল সূচক সরবরাহ করতে হবে যা একটি থ্রেড সেট করে এবং অপেক্ষায় থাকে যখন অন্য থ্রেডটি পর্যায়ক্রমে পরীক্ষা করে এবং সানন্দে বের হয়। .NET 4, একটি কাঠামো এই কাজের জন্য বিশেষভাবে ডিজাইন করা রয়েছে CancellationToken


8

আপনার সরাসরি এটি করার চেষ্টা করা উচিত নয়। বাতিলকরণ টোকেনের সাথে কাজ করার জন্য আপনার কার্যগুলি ডিজাইন করুন এবং এগুলি এটিকে বাতিল করুন।

তদতিরিক্ত, আমি আপনার মূল থ্রেডটিও বাতিলকরণ টোকেনের মাধ্যমে ফাংশনে পরিবর্তনের পরামর্শ দেব। কল Thread.Abort()করা একটি খারাপ ধারণা - এটি বিভিন্ন সমস্যার সমাধান করতে পারে যা নির্ণয় করা খুব কঠিন। পরিবর্তে, এই থ্রেডটি আপনার কাজগুলি ব্যবহার করে এমন একই বাতিলকরণ ব্যবহার CancellationTokenSourceকরতে পারে - এবং একইটি আপনার সমস্ত কার্য এবং আপনার মূল থ্রেড বাতিল করতে ট্রিগার করতে ব্যবহার করা যেতে পারে ।

এটি অনেক সহজ এবং নিরাপদ, নকশার দিকে নিয়ে যাবে।


8

টাস্ক.ফ্যাক্টরি.স্টার্টনিউ () তে বেনামে পদ্ধতি ব্যবহার না করে বাতিলকরণ টোকেন কীভাবে ব্যবহার করবেন সে সম্পর্কে প্রেরাক কে-র প্রশ্নের উত্তর দিতে, আপনি এমএসডিএন উদাহরণে দেখানো হিসাবে স্টার্টনিউ () দিয়ে যে পদ্ধতিটি শুরু করছেন তাতে প্যারামিটার হিসাবে বাতিলকরণ টোকেনকে পাস করেন এখানে

যেমন

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

Task.Factory.StartNew( () => DoSomeWork(1, token), token);

static void DoSomeWork(int taskNum, CancellationToken ct)
{
    // Do work here, checking and acting on ct.IsCancellationRequested where applicable, 

}

7

আমি কোনও কাজ বাতিল করতে একটি মিশ্র পদ্ধতির ব্যবহার করি।

  • প্রথমত, আমি এটা সবিনয়ে বাতিল করতে ব্যবহার করে চেষ্টা করছি বাতিলকরণ
  • যদি এটি এখনও চলছে (উদাহরণস্বরূপ বিকাশকারীর ভুলের কারণে), তবে এটি পুরাতন-স্কুল পরিত্যক্ত পদ্ধতিটি ব্যবহার করে খারাপ আচরণ করুন এবং হত্যা করুন ।

নীচে একটি উদাহরণ চেকআউট করুন:

private CancellationTokenSource taskToken;
private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false);

void Main()
{
    // Start a task which is doing nothing but sleeps 1s
    LaunchTaskAsync();
    Thread.Sleep(100);
    // Stop the task
    StopTask();
}

/// <summary>
///     Launch task in a new thread
/// </summary>
void LaunchTaskAsync()
{
    taskToken = new CancellationTokenSource();
    Task.Factory.StartNew(() =>
        {
            try
            {   //Capture the thread
                runningTaskThread = Thread.CurrentThread;
                // Run the task
                if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000))
                    return;
                Console.WriteLine("Task finished!");
            }
            catch (Exception exc)
            {
                // Handle exception
            }
        }, taskToken.Token);
}

/// <summary>
///     Stop running task
/// </summary>
void StopTask()
{
    // Attempt to cancel the task politely
    if (taskToken != null)
    {
        if (taskToken.IsCancellationRequested)
            return;
        else
            taskToken.Cancel();
    }

    // Notify a waiting thread that an event has occurred
    if (awaitReplyOnRequestEvent != null)
        awaitReplyOnRequestEvent.Set();

    // If 1 sec later the task is still running, kill it cruelly
    if (runningTaskThread != null)
    {
        try
        {
            runningTaskThread.Join(TimeSpan.FromSeconds(1));
        }
        catch (Exception ex)
        {
            runningTaskThread.Abort();
        }
    }
}

4

টোকেনগুলি বাতিলকরণের মাধ্যমে বাতিল করার জন্য কার্যগুলিতে প্রথম শ্রেণির সমর্থন রয়েছে । বাতিল টোকেন দিয়ে আপনার টাস্কগুলি তৈরি করুন এবং এগুলির মাধ্যমে স্পষ্টভাবে কাজগুলি বাতিল করুন।


4

CancellationTokenকাজটি বাতিল হয়ে যায় কিনা তা নিয়ন্ত্রণ করতে আপনি একটি ব্যবহার করতে পারেন । আপনি কি এটি শুরুর আগে ("কোনও বিষয় নয়, আমি ইতিমধ্যে এটি করেছি") বন্ধ করার বিষয়ে কথা বলছি না, বা আসলে এটি মাঝখানে বাধা দিচ্ছি? যদি প্রাক্তন হয় CancellationTokenতবে সাহায্যকারী হতে পারে; যদি দ্বিতীয়টি হয় তবে আপনাকে সম্ভবত আপনার নিজের "জামিন আউট" প্রক্রিয়াটি প্রয়োগ করতে হবে এবং আপনার দ্রুত ব্যর্থ হওয়া উচিত কিনা তা টাস্ক কার্যকর করার উপযুক্ত পয়েন্টগুলি পরীক্ষা করতে হবে (আপনি এখনও সাহায্যের জন্য বাতিলকরণ টোকেন ব্যবহার করতে পারেন তবে এটি কিছুটা বেশি ম্যানুয়াল)।

এমএসডিএন এর কার্যগুলি বাতিল করার বিষয়ে একটি নিবন্ধ রয়েছে: http://msdn.microsoft.com/en-us/library/dd997396.aspx


3

থ্রেডপুলে টাস্ক কার্যকর করা হচ্ছে (কমপক্ষে, যদি আপনি ডিফল্ট কারখানাটি ব্যবহার করে থাকেন), সুতরাং থ্রেডটি বাতিল করা কার্যগুলিকে প্রভাবিত করতে পারে না। বিসর্জন কার্যগুলির জন্য, এমএসডিএন-তে টাস্ক বাতিলকরণ দেখুন ।


1

আমি চেষ্টা করেছি CancellationTokenSourceকিন্তু আমি এটি করতে পারি না। এবং আমি আমার নিজস্ব উপায়ে এটি করেছি। এবং এটি কাজ করে।

namespace Blokick.Provider
{
    public class SignalRConnectProvider
    {
        public SignalRConnectProvider()
        {
        }

        public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.

        public async Task<string> ConnectTab()
        {
            string messageText = "";
            for (int count = 1; count < 20; count++)
            {
                if (count == 1)
                {
                //Do stuff.
                }

                try
                {
                //Do stuff.
                }
                catch (Exception ex)
                {
                //Do stuff.
                }
                if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
                {
                    return messageText = "Task stopped."; //4-) And so return and exit the code and task.
                }
                if (Connected)
                {
                //Do stuff.
                }
                if (count == 19)
                {
                //Do stuff.
                }
            }
            return messageText;
        }
    }
}

পদ্ধতিটি কল করার আর একটি ক্লাস:

namespace Blokick.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MessagePerson : ContentPage
    {
        SignalRConnectProvider signalR = new SignalRConnectProvider();

        public MessagePerson()
        {
            InitializeComponent();

            signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.

            if (signalR.ChatHubProxy != null)
            {
                 signalR.Disconnect();
            }

            LoadSignalRMessage();
        }
    }
}

0

আপনি যদি কোনও কাজটি তার নিজের থ্রেডে তৈরি করতে এবং Abortতার Threadঅবজেক্টটিতে কল করতে পারেন তবে আপনি থ্রেডের মতো কোনও কাজকে বাতিল করতে পারেন । ডিফল্টরূপে, একটি টাস্ক একটি থ্রেড পুল থ্রেড বা কলিং থ্রেডে চালিত হয় - যার মধ্যে আপনি সাধারণত বাতিল করতে চান না।

কার্যটি নিজস্ব থ্রেড পেয়েছে তা নিশ্চিত করতে, থেকে প্রাপ্ত একটি কাস্টম শিডিয়ুলার তৈরি করুন TaskScheduler। আপনার প্রয়োগে QueueTask, একটি নতুন থ্রেড তৈরি করুন এবং কার্য সম্পাদন করতে এটি ব্যবহার করুন। পরবর্তীতে, আপনি থ্রেড, যা একটি সঙ্গে একটি সমালোচনা রাজ্যের সম্পন্ন টাস্ক কারণ হবে বাতিল করতে ThreadAbortException

এই টাস্ক শিডিয়ুলারটি ব্যবহার করুন:

class SingleThreadTaskScheduler : TaskScheduler
{
    public Thread TaskThread { get; private set; }

    protected override void QueueTask(Task task)
    {
        TaskThread = new Thread(() => TryExecuteTask(task));
        TaskThread.Start();
    }

    protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
    protected override bool NotSupportedException(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}

আপনার কাজটি এভাবে শুরু করুন:

var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);

পরে, আপনি এর সাথে গর্ভপাত করতে পারেন:

scheduler.TaskThread.Abort();

নোট করুন যে কোনও থ্রেড বাতিল করার বিষয়ে সতর্কতা এখনও প্রযোজ্য:

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


এই কোডটি একটি রানটাইম ব্যতিক্রম সহ ব্যর্থ: সিস্টেম.আইনডিয়োপলপেশন এক্সসেপশন: রানস সিনক্রোনাসলি ইতিমধ্যে শুরু করা কোনও কার্যের জন্য ডাকা যাবে না।
থিওডর জৌলিয়াস

1
পছন্দ করুন ধন্যবাদ। আমি কোডটি সংশোধন করেছি এবং উত্তরটি সাধারণত উন্নত করেছি।
এডওয়ার্ড ব্রেই

1
ইয়াপ, এটি বাগটি ঠিক করেছে। এটির উল্লেখ করা উচিত এমন আরও একটি সতর্কতা হ'ল Thread.Abortএটি .NET কোর সমর্থিত নয়। এটির ব্যবহারের চেষ্টা এখানে ব্যতিক্রমের ফলাফল: সিস্টেম.প্লাটফর্ম নটসপোর্টড এক্সসেপশন: এই প্ল্যাটফর্মে থ্রেড অ্যাওর্ট সমর্থিত নয়। একটি তৃতীয় সতর্কতা হ'ল SingleThreadTaskSchedulerপ্রতিশ্রুতি-শৈলীর কার্যগুলির সাথে asyncডেলিগেটসদের সাথে তৈরি টাস্কগুলির সাথে কার্যকরভাবে ব্যবহার করা যাবে না । উদাহরণস্বরূপ একটি এম্বেড await Task.Delay(1000)থাকা কোনও থ্রেডে চালিত হয় না, সুতরাং এটি থ্রেড ইভেন্টগুলি থেকে প্রভাবিত হবে।
থিওডর জৌলিয়াস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.