एक सूत्र में, मैं कुछ बनाता हूं System.Threading.Task
और प्रत्येक कार्य शुरू करता हूं ।
जब मैं .Abort()
थ्रेड को मारने के लिए करता हूं , तो कार्य निरस्त नहीं किए जाते हैं।
मैं .Abort()
अपने कार्यों को कैसे प्रसारित कर सकता हूं ?
एक सूत्र में, मैं कुछ बनाता हूं System.Threading.Task
और प्रत्येक कार्य शुरू करता हूं ।
जब मैं .Abort()
थ्रेड को मारने के लिए करता हूं , तो कार्य निरस्त नहीं किए जाते हैं।
मैं .Abort()
अपने कार्यों को कैसे प्रसारित कर सकता हूं ?
जवाबों:
आप नहीं कर सकते। कार्य थ्रेड पूल से पृष्ठभूमि थ्रेड का उपयोग करते हैं। एबॉर्ट विधि का उपयोग करके थ्रेड को रद्द करने की अनुशंसा नहीं की जाती है। आप निम्नलिखित ब्लॉग पोस्ट पर एक नज़र डाल सकते हैं जो रद्दीकरण टोकन का उपयोग करके कार्यों को रद्द करने का एक उचित तरीका बताते हैं। यहाँ एक उदाहरण है:
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();
}
}
Task.Wait(TimeSpan / int)
इसे बाहर से समय (समय-आधारित) देने के लिए उपयोग करना।
Task
? की तरह कुछ: public int StartNewTask(Action method)
। StartNewTask
मेरे Task
द्वारा बनाई गई विधि के अंदर Task task = new Task(() => method()); task.Start();
:। तो मैं कैसे प्रबंधित कर सकता हूं CancellationToken
? मैं यह भी जानना चाहूंगा कि क्या Thread
मुझे एक तर्क को लागू करने की आवश्यकता है अगर यह जांचने के लिए कि क्या कुछ टास्क हैं जो अभी भी लटके हुए हैं और इसलिए जब उन्हें मारना है Form.Closing
। के साथ Threads
मैं का उपयोग करें Thread.Abort()
।
यदि आप उस टास्क को कैप्चर करते हैं जिसमें टास्क चल रहा है, तो एक टास्क को आसानी से संभव है। इसे प्रदर्शित करने के लिए एक उदाहरण कोड है।
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();
}
मैंने इसके लिए सबसे आम उपयोग के मामले को दिखाने के लिए टास्क.रून () का उपयोग किया - पुराने एकल-थ्रेडेड कोड के साथ टास्क के आराम का उपयोग करते हुए, जो यह निर्धारित करने के लिए कि रद्द किया जाना चाहिए या नहीं रद्द करने के लिए कैंसिलेशनटॉकनसोर्स स्रोत का उपयोग नहीं करता है।
CancellationToken
समर्थन नहीं है ...
CancellationToken
या एक और भी सरल समाधान है कि दौड़-हालत मुक्त हैं पर विचार किया जाना चाहिए। उपरोक्त कोड केवल विधि का वर्णन करता है, उपयोग का क्षेत्र नहीं।
thread
स्थानीय चर में पारित हो जाएगा )। आपके कोड में आप मुख्य धागे को समाप्त कर सकते हैं, जो कि आप वास्तव में नहीं चाहते हैं। शायद एक जाँच करें कि क्या थ्रेड्स गर्भपात से पहले के समान हैं, अगर आप गर्भपात करने के लिए जोर देते हैं, तो अच्छा होगा
जैसा कि इस पोस्ट से पता चलता है, यह निम्नलिखित तरीके से किया जा सकता है:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
यद्यपि यह काम करता है, यह इस तरह के दृष्टिकोण का उपयोग करने के लिए अनुशंसित नहीं है। यदि आप उस कोड को नियंत्रित कर सकते हैं जो कार्य में निष्पादित होता है, तो आप रद्दीकरण की उचित हैंडलिंग के साथ बेहतर होंगे।
इस तरह की बात तर्कपूर्ण कारणों में से एक है कि क्यों Abort
निकाला जाता है। सबसे पहले और सबसे महत्वपूर्ण, यदि संभव हो तो एक धागा को रद्द करने या रोकने के लिए उपयोग न करें Thread.Abort()
। Abort()
केवल एक थ्रेड को जबरदस्ती मारने के लिए इस्तेमाल किया जाना चाहिए जो समय पर फैशन में रुकने के लिए अधिक शांतिपूर्ण अनुरोधों का जवाब नहीं दे रहा है।
कहा जा रहा है, आपको एक साझा रद्दीकरण संकेतक प्रदान करने की आवश्यकता है जो एक थ्रेड सेट करता है और प्रतीक्षा करता है जबकि दूसरा थ्रेड समय-समय पर जाँच और अनुग्रह से बाहर निकलता है। नेट 4, एक संरचना इस उद्देश्य के लिए विशेष रूप से डिजाइन शामिल हैं CancellationToken
।
आपको इसे सीधे करने की कोशिश नहीं करनी चाहिए। रद्द करने के लिए अपने कार्यों को डिज़ाइन करें रद्द करें , और उन्हें इस तरह रद्द करें।
इसके अलावा, मैं रद्द करने के लिए अपने मुख्य सूत्र को रद्द करने की सलाह दूंगा। कॉलिंग Thread.Abort()
एक बुरा विचार है - इससे विभिन्न समस्याएं हो सकती हैं जिनका निदान करना बहुत मुश्किल है। इसके बजाय, वह धागा उसी रद्दीकरण का उपयोग कर सकता है जिसे आपके कार्य उपयोग करते हैं - और उसी CancellationTokenSource
का उपयोग आपके सभी कार्यों और आपके मुख्य धागे को रद्द करने के लिए किया जा सकता है ।
यह एक सरल, और सुरक्षित, डिजाइन को जन्म देगा।
टास्क फैक्ट्री.टार्टन्यू () में अनाम विधि का उपयोग नहीं करने पर कैंसेलेशनटॉकेन्स का उपयोग करने के तरीके के बारे में Prerak K के प्रश्न का उत्तर देने के लिए, आप MSN उदहारण में दिखाए गए तरीके से एक पैरामीटर के रूप में CancellationToken पास करें, जैसा कि MSDN उदाहरण में दिखाया गया है। यहाँ ।
जैसे
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,
}
मैं एक कार्य को रद्द करने के लिए एक मिश्रित दृष्टिकोण का उपयोग करता हूं।
नीचे एक उदाहरण देखें:
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();
}
}
}
निरस्तीकरण टोकन के माध्यम से रद्द करने के लिए कार्य में प्रथम श्रेणी का समर्थन है । रद्दीकरण टोकन के साथ अपने कार्य बनाएं, और इन के माध्यम से कार्यों को स्पष्ट रूप से रद्द करें।
आप CancellationToken
नियंत्रण का उपयोग कर सकते हैं कि क्या कार्य रद्द हो गया है। क्या आप इसे शुरू करने से पहले इसे खत्म करने के बारे में बात कर रहे हैं ("कोई बात नहीं, मैंने पहले ही यह कर लिया है"), या वास्तव में इसे बीच में रोकना? यदि पूर्व,CancellationToken
सहायक हो सकता है; यदि बाद में, आपको संभवतः अपने स्वयं के "बेल आउट" तंत्र को लागू करने और कार्य निष्पादन में उचित बिंदुओं पर जांच करने की आवश्यकता होगी कि क्या आपको तेजी से विफल होना चाहिए (आप अभी भी रद्दीकरण का उपयोग कर सकते हैं आपकी मदद करने के लिए, लेकिन यह थोड़ा और अधिक मैनुअल है)।
MSDN के पास कार्य रद्द करने के बारे में एक लेख है: http://msdn.microsoft.com/en-us/library/dd997396.aspx
थ्रेडपूल पर टास्क निष्पादित किए जा रहे हैं (कम से कम, यदि आप डिफ़ॉल्ट फ़ैक्टरी का उपयोग कर रहे हैं), इसलिए थ्रेड को निरस्त करने से कार्यों को प्रभावित नहीं किया जा सकता है। गर्भपात के कार्यों के लिए, msdn पर टास्क कैंसिलेशन देखें ।
मैंने कोशिश की 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();
}
}
}
आप किसी कार्य को थ्रेड की तरह निरस्त कर सकते हैं यदि आप कार्य को अपने स्वयं के थ्रेड पर बनाने और 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
करने से स्थिर निर्माणकर्ताओं को निष्पादित करने या अप्रबंधित संसाधनों की रिहाई को रोका जा सकता है।
Thread.Abort
.NET कोर पर समर्थित नहीं है। इसका उपयोग करने का प्रयास एक अपवाद के रूप में होता है: System.PlatformNotSupportedException: थ्रेड एबोर्ट इस प्लेटफ़ॉर्म पर समर्थित नहीं है। एक तीसरा चेतावनी यह है कि प्रतिनिधियों SingleThreadTaskScheduler
के साथ बनाए गए कार्यों के साथ, दूसरे शब्दों में, वादा-शैली के कार्यों के साथ प्रभावी ढंग से उपयोग नहीं किया जा सकता है async
। उदाहरण के लिए await Task.Delay(1000)
कोई धागा में एक एम्बेडेड रन, इसलिए यह अप्रभावित होना धागा घटना है।