Nulls в Producer - C#

Узнай цену своей работы

Формулировка задачи:

Здравствуйте. Прошу помочь, потому как сам уже в душе не я... знаю как это разрешить
while (true)
            {
                Block block = null;
                try
                {
                    lock (this.inputLockObj)
                    {
                        if (this.input.Count > 0)
                        {
                            block = this.input.Dequeue();
 
                            if (block == null)
                                return;
                        }
 
                    }
 
                    this.readAdd.Set();
 
                    if (block != null)
                    {
                        action.Act(block);
                        this.EnqueueHandledBlock(block);
                    }
                    else
                    {
                        this.readGet.WaitOne();
                    }
 
                }
                catch (ThreadAbortException e)
                {
                    Console.WriteLine(e.Message);
                    return;
                }
                catch (Exception e)
                {
                    callback?.Invoke(e.Message);
                    return;
                }
            }
Застопорил на том, что потоки не завершаются после окончания. Т.е. один из рабочих потоков при этом очень быстро завершает самый последний блок и успевает пойти на следующий круг раньше, чем основной поток дождётся producer Join и положит туда nulls. В этом случае поток повиснет в куске
this.readGet.WaitOne();
, т.к. не войдет в блок
if (this.input.Count > 0)
                        {
                            block = this.input.Dequeue();
 
                            if (block == null)
                                return;
                        }
Но я понятия не приложу как это реализовать, паттерн головного мозга. Пользовался https://rsdn.org/article/dotnet/CSThreading1.xml

Решение задачи: «Nulls в Producer»

textual
Листинг программы
class ProducerConsumer
{
    private Semaphore _workLimit;
    private ManualResetEvent _awaiter = new ManualResetEvent(true);
    private object _locker = new object();
    private Queue<Action> _work = new Queue<Action>();
    private int _threads;
    private int _abortsPending;
    
    public ProducerConsumer(int workLimit)
    {
        _workLimit = new Semaphore(workLimit, workLimit);
    }
    
    public void AddWorker()
    {
        var thread = new Thread(DoWork);
        thread.Start();
        
        lock (_locker)
            _threads++;
    }
    
    public void RemoveWorker()
    {
        lock (_locker)
            _abortsPending++;
    }
    
    public void Join()
    {       
        _awaiter.WaitOne();
 
        lock (_locker)
        {
            _abortsPending += _threads - _abortsPending;
            Monitor.PulseAll(_locker);
        }
    }
 
    public void AddWork(Action workItem)
    {
        _workLimit.WaitOne();
        
        lock (_locker)
        {
            _work.Enqueue(workItem);
            Monitor.Pulse(_locker);
            _awaiter.Reset();
        }
    }
    
    private void DoWork()
    {
        while (true)
        {
            Action action = null;
 
            lock (_locker)
            {
                if (_work.Count == 0)
                    _awaiter.Set();
                    
                if (_abortsPending > 0)
                {
                    _abortsPending--;
                    _threads--;
                    return;
                }
 
                while (!_work.Any())
                {
                    Monitor.Wait(_locker);
 
                    if (_abortsPending > 0)
                    {
                        _abortsPending--;
                        _threads--;
                        return;
                    }
                }
 
                action = _work.Dequeue();
            }
 
            action();
            
            _workLimit.Release();
        }
    }
}
 
void Main()
{
    var pc = new ProducerConsumer(1);
    
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
    pc.AddWorker();
 
    pc.AddWork(() => { Console.WriteLine("1"); Thread.Sleep(1000); });
    pc.AddWork(() => Console.WriteLine("2"));
    pc.AddWork(() => Console.WriteLine("3"));
    pc.AddWork(() => { Console.WriteLine("4"); Thread.Sleep(1000); });
    
    Console.WriteLine("Join");
    pc.Join();
    Console.WriteLine("End");
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

5   голосов , оценка 4 из 5
Похожие ответы