Что гарантирует С # SemaphoreSlim? Это полный барьер памяти? В чем мы можем быть уверены в коде между двумя разными семафорами Wait () и Release ()? - PullRequest
1 голос
/ 28 февраля 2020

Что гарантирует С # SemaphoreSlim? Это полный барьер памяти? В чем мы можем быть уверены в коде между двумя разными семафорами Wait () и Release ()? Имеет последовательность различных методов SemaphoreSlim Wait (), Release () и Interlocked и Volatile. Запись / чтение всегда поддерживать порядок в каждой теме?

    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));
    }
}
...