Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.02.2020, 23:12   #1
ccccfr
Пользователь
 
Регистрация: 26.02.2011
Сообщений: 12
По умолчанию Блокирующая очередь без lock и Mutex на SemaphoreSlim.

Блокирующая кольцевая очередь. Будет ли правильно работать такой код? Нужен ли здесь Volatile.Read, Volatile.Write?
Идея такая. Два SemaphoreSlim не дают одновременно писать и читать один и тот же элемент массива. Вроде как, все нужные барьеры памяти тут есть. Своевременное обновление значения для каждого потока (кэш ядер) обеспечивают Volatile.Read, Volatile.Write. Или тут можно без них? Или для массивов это работать не будет так?

Псевдокод:
Код:
    public class BlockingRingQueue<T> where T: class
    {
        T[] buf = new T[BUFSIZE];
        int start = 0;
        int end = 0;
        SemaphoreSlim canReadCountSemaphoreSlim = new SemaphoreSlim(0);
        SemaphoreSlim canWriteCountSemaphoreSlim = new SemaphoreSlim(BUFSIZE);
        
        public T Dequeue()
        {            
            canReadCountSemaphoreSlim.Wait(); 
            
            int i = Interlocked.Decrement(ref end);
            T val = Volatile.Read(ref buf[i]);                        
            
            canWriteCountSemaphoreSlim.Release();            
            return val;            
        }        
        public void Enqueue(T val)        
        {                        
            canWriteCountSemaphoreSlim.Wait();
            
            int i = Interlocked.Decrement(ref start);
            Volatile.Write(ref buf[i], val);
                        
            canReadCountSemaphoreSlim.Release();            
        }
}
Полный код:
Код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

using System.Threading;

namespace Program
{
    public class BlockingRingQueue<T> where T: class
    {
        const int BUFSIZE_LOG2 = 10;
        const int BUFSIZE = 1 << BUFSIZE_LOG2;
        
        T[] buf = new T[BUFSIZE];
        int start = 0;
        int end = 0;
        SemaphoreSlim canReadCountSemaphoreSlim = new SemaphoreSlim(0);
        SemaphoreSlim canWriteCountSemaphoreSlim = new SemaphoreSlim(BUFSIZE);
        
        public T Dequeue()
        {            
            canReadCountSemaphoreSlim.Wait();
            
            int i = Interlocked.Decrement(ref end);
            i = PositiveMod(i, BUFSIZE);
            T val = Volatile.Read(ref buf[i]);
                        
            canWriteCountSemaphoreSlim.Release();            
            return val;            
        }
        
        public void Enqueue(T val)        
        {                        
            canWriteCountSemaphoreSlim.Wait();
            
            int i = Interlocked.Decrement(ref start);
            i = PositiveMod(i, BUFSIZE);
            Volatile.Write(ref buf[i], val);
                        
            canReadCountSemaphoreSlim.Release();            
        }
        
        static int PositiveMod(int a, int b) => ((a % b) + b) % b;
    } 
        
    
    public class Program
    {
        const int READ_THREAD_COUNT = 3;
        static BlockingRingQueue<string> queue = new BlockingRingQueue<string>();
            
        public static void Main(string[] args)
        {
            new Thread(() => Pushing("ABCD")) { Name = "0" }.Start();
            
            for(int i = 1; i <= READ_THREAD_COUNT; i++)
                    new Thread(Poping) { Name = i.ToString() }.Start();
        }
        
        public static void Poping() 
        {
            while(true)
            {
                RandSpinWait();
                var val = queue.Dequeue();
                if("" == val)
                    break;
                    
                Console.WriteLine(val + Thread.CurrentThread.Name + ' ');
            }
            //Console.WriteLine('!' + Thread.CurrentThread.Name + ' ');
        }
        
        public static void Pushing(string chars) 
        {
            RandSpinWait();

            var vals = chars.ToCharArray().Select(c => $"{c}")
                .Concat(Enumerable.Repeat("",READ_THREAD_COUNT));
                        
            foreach(string v in vals)
                queue.Enqueue(v);            
        }
        
        public static void RandSpinWait() => Thread.SpinWait(new Random().Next(1));
    }
}
ccccfr вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Mutex Abdura Python 0 24.04.2019 20:45
c# одну очередь однозначных чисел, а вторую очередь двузначных чисел. Перемножьте соответственные элементы двух очередей и организуйте третью очередь Maksim221 Фриланс 2 09.06.2018 18:22
mutex goluzov Общие вопросы C/C++ 3 06.01.2014 09:21
вводим 15 элементов в очередь, затем выводим на экран эту очередь и добавил в очередь еще один элемент. Потом удаляем любой элемен Xumera C++ Builder 2 07.12.2013 13:56
Использование mutex Sparky Помощь студентам 1 29.05.2010 16:24