c# - लंबे चलने वाले कार्य के बाद सही तरीके से साफ कैसे करें रद्द कर दिया जाता है



c#-4.0 concurrency (1)

सावधानीपूर्वक प्रोग्रामिंग केवल एक चीज है जो इसे कटौती करने वाला है। यहां तक ​​कि अगर आप ऑपरेशन रद्द करते हैं, तो आपके पास एक लंबित कार्रवाई हो सकती है जो फैशनेबल मात्रा में पूरा नहीं हो रही है यह बहुत अच्छी तरह से अवरुद्ध ऑपरेशन हो सकता है जो डेडलॉक हो गया है। इस मामले में आपका प्रोग्राम वास्तव में समाप्त नहीं होगा

उदाहरण के लिए, अगर मैं अपनी क्लीनअप विधि को कई बार या बिना कॉल किए कॉल करता हूं तो पहले मुझे यह लग रहा है कि यह दुर्घटनाग्रस्त हो रहा है।

सफाई के दौरान 2 सेकेंड का समय समाप्त हो गया, नियोजित की तुलना में अधिक मनमाना महसूस होता है, और मैं वास्तव में यह सुनिश्चित करने के लिए जाता हूं कि चीजों को ठीक तरह से बंद या क्रैश / हैंग (आप कभी भी अज्ञात स्थिति में समवर्ती सामान नहीं छोड़ना चाहते)

इसके अलावा, IsRunning स्पष्ट रूप से निर्धारित है, ऑब्जेक्ट की स्थिति से अनुमानित नहीं है

प्रेरणा के लिए मैं चाहता हूं कि आप हाल ही में लिखे गए समान श्रेणी को देखना चाहते हैं, यह एक निर्माता / उपभोक्ता पैटर्न है जो यह पृष्ठभूमि के थ्रेड में काम करता है। आप CodePlex पर उस स्रोत कोड को पा सकते हैं हालांकि, यह एक बहुत विशिष्ट समस्या को हल करने के लिए इंजीनियर था।

यहां, रद्द करने का एक विशिष्ट प्रकार को शामिल करके हल किया जाता है जो केवल कार्यकर्ता थ्रेड पहचानता है और इस तरह बंद हो रहा है। यह यह भी सुनिश्चित करता है कि मैं लंबित कार्य को कभी भी रद्द नहीं करता, केवल काम की पूरी इकाइयों को माना जाता है।

इस परिस्थिति को बेहतर बनाने के लिए आप वर्तमान कार्य के लिए एक अलग टाइमर रख सकते हैं और रद्द कर सकते हैं अगर अपूर्ण या रोलबैक अपूर्ण काम कर सकते हैं। अब, व्यवहार जैसे लेनदेन को लागू करना कुछ मुकदमेबाजी और त्रुटि लेने जा रहा है क्योंकि आपको हर संभव कोने के मामले को देखने और खुद से पूछने की ज़रूरत है, तो क्या होता है यदि कार्यक्रम यहां क्रैश हो जाता है? आदर्श रूप से ये सभी कोड पथ एक पुनर्प्राप्ति योग्य या ज्ञात राज्य से आगे बढ़ते हैं, जिससे आप अपना काम फिर से शुरू कर सकते हैं। लेकिन जैसा कि मुझे लगता है कि आपने पहले से ही अनुमान लगाया है, वह सावधानीपूर्वक प्रोग्रामिंग और कई परीक्षणों को ले जाएगा।

मैंने एक ऐसा वर्ग बनाया है जिसका उद्देश्य एक कतार में समवर्ती पहुंच के नियंत्रण को दूर करना है

कक्षा को एक धागे पर तत्काल बनाने के लिए डिज़ाइन किया गया है, जिसे कई धागे से लिखा गया है और बाद में एक एकल धागा से पढ़ें।

मेरे पास कक्षा में उत्पन्न एक भी लंबे समय तक चलने वाला कार्य है जो ब्लॉकिंग पाश प्रदर्शन करेगा और एक घटना को आग लगा देगा यदि कोई आइटम सफलतापूर्वक dequeued है।

मेरा प्रश्न यह है: क्या मुझे लंबे समय से चलने वाले कार्य को रद्द करने का क्रियान्वयन है और बाद में CancellationTokenSource ऑब्जेक्ट का सही इस्तेमाल / रीसेट / रीसेट करता है?

आदर्श रूप से, मैं एक सक्रिय ऑब्जेक्ट को रोकना और कतार में जोड़ने के लिए उपलब्धता को बनाए रखने में पुनरारंभ होने में सक्षम होना चाहता हूं।

मैंने पीटर ब्रोमबर्ग के लेख को एक आधार के रूप में प्रयोग किया है: निर्माता / उपभोक्ता कतार और अवरोधन सी # 4.0 में संकलन

नीचे कोड:

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Test
{
    public delegate void DeliverNextQueuedItemHandler<T>(T item);

public sealed class SOQueueManagerT<T> 
{

    ConcurrentQueue<T> _multiQueue;
    BlockingCollection<T> _queue;
    CancellationTokenSource _canceller;
    Task _listener = null;

    public event DeliverNextQueuedItemHandler<T> OnNextItem;

    public bool IsRunning { get; private set; }
    public int QueueSize
    {
        get
        {
            if (_queue != null)
                return _queue.Count;
            return -1;
        }
    }

    public CancellationTokenSource CancellationTokenSource
    {
        get
        {
            if (_canceller == null)
                _canceller = new CancellationTokenSource();

            return _canceller;
        }
    }

    public SOQueueManagerT()
    {
        _multiQueue = new ConcurrentQueue<T>();
        _queue = new BlockingCollection<T>(_multiQueue);

        IsRunning = false;
    }

    public void Start()
    {
        if (_listener == null)
        {


            IsRunning = true;

            _listener = Task.Factory.StartNew(() =>
            {

                while (!CancellationTokenSource.Token.IsCancellationRequested)
                {
                    T item;
                    if (_queue.TryTake(out item, 100))
                    {
                        if (OnNextItem != null)
                        {

                            OnNextItem(item);
                        }
                    }

                }
            },
            CancellationTokenSource.Token,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default);
        }
    }

    public void Stop()
    {
        if (_listener != null)
        {
            CancellationTokenSource.Cancel();
            CleanUp();
        }
    }

    public void Add(T item)
    {
        _queue.Add(item);
    }

    private void CleanUp()
    {
        _listener.Wait(2000);
        if (_listener.IsCompleted)
        {
            IsRunning = false;
            _listener = null;
            _canceller = null;
        }
    }


 }
}

अद्यतन यहाँ मैं अंत में साथ चले गए हैं क्या है यह सही नहीं है, लेकिन अभी तक नौकरी कर रही है

public sealed class TaskQueueManager<T> 
{
    ConcurrentQueue<T> _multiQueue;
    BlockingCollection<T> _queue;
    CancellationTokenSource _canceller;
    Task _listener = null;

    public event DeliverNextQueuedItemHandler<T> OnNextItem;

    public bool IsRunning
    {
        get
        {
            if (_listener == null)
                return false;
            else if (_listener.Status == TaskStatus.Running ||
                _listener.Status == TaskStatus.Created ||
                _listener.Status == TaskStatus.WaitingForActivation ||
                _listener.Status == TaskStatus.WaitingToRun ||
                _listener.IsCanceled)
                return true;
            else
                return false;
        }
    }
    public int QueueSize
    {
        get
        {
            if (_queue != null)
                return _queue.Count;
            return -1;
        }
    }

    public TaskQueueManager()
    {
        _multiQueue = new ConcurrentQueue<T>();
        _queue = new BlockingCollection<T>(_multiQueue);
    }

    public void Start()
    {
        if (_listener == null)
        {
            _canceller = new CancellationTokenSource();

            _listener = Task.Factory.StartNew(() =>
            {
                while (!_canceller.Token.IsCancellationRequested)
                {
                    T item;
                    if (_queue.TryTake(out item, 100))
                    {
                        if (OnNextItem != null)
                        {
                            try
                            {
                                OnNextItem(item);
                            }
                            catch (Exception e)
                            {
                                //log or call an event
                            }
                        }
                    }
                }
            },
            _canceller.Token,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Default);
        }
    }

    public void Stop()
    {
        if (_listener != null)
        {
            _canceller.Cancel();

            if (_listener.IsCanceled && !_listener.IsCompleted)
                _listener.Wait();

            _listener = null;
            _canceller = null;
        }
    }

    public void Add(T item)
    {
        if (item != null)
        {
            _queue.Add(item);
        }
        else
        {
            throw new ArgumentNullException("TaskQueueManager<" + typeof(T).Name + ">.Add item is null");
        }
    }
}




cancellation