Tools.Collections

1) Добавлен проект Tools.Collections.Concurrent.AsyncBuffer Потокобезопасный

1/7/2021 4:27:32 PM

Changes

.gitignore 28(+26 -2)

Details

.gitignore 28(+26 -2)

diff --git a/.gitignore b/.gitignore
index f5eb3a9..ebb391b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,17 @@
 
+src/ManagetLinkCollection/.vs/ManagetLinkCollection/*
+
+
+src/ManagetLinkCollection/ManagetLinkCollection.ConsoleTest/bin/*
+src/ManagetLinkCollection/ManagetLinkCollection.ConsoleTest/obj/*
+
+src/ManagetLinkCollection/ManagetLinkCollection/bin/*
+src/ManagetLinkCollection/ManagetLinkCollection/obj/*
+
+src/ManagetLinkCollection/packages/*
+
+
+
 src/Tools.Collections/.vs/*
 /.vs/*
 
@@ -17,5 +30,16 @@ src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/obj/*
 src/Tools.Collections/Tools.Collections.ConsoleTest/bin/*
 src/Tools.Collections/Tools.Collections.ConsoleTest/obj/*
 
-/src/Tools.Collections/NugetBuild/Packages/*
-/src/Tools.Collections/NugetBuild/nuget.exe
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/obj/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj.user
+
+src/Tools.Collections/Tools.CancellationTokenAsync/bin/*
+src/Tools.Collections/Tools.CancellationTokenAsync/obj/*
+
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBufferюUnitTest/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBufferюUnitTest/obj/*
+
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/obj/*
+src/Tools.Collections/packages/*
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs
new file mode 100644
index 0000000..098a5cf
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs
@@ -0,0 +1,40 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest.Fake
+{
+    enum EnumTestPrioriry
+    {
+        Low = 0,
+        MiddleLow = 25,
+        Middle = 50,
+        MiddleHish = 75,
+        High = 100
+    }
+
+    class PriorityComparer
+        : IComparer<EnumTestPrioriry>
+    {
+        public Func<EnumTestPrioriry, EnumTestPrioriry,int> CompareFunc { set; get; }
+        public int Compare(EnumTestPrioriry x, EnumTestPrioriry y)
+        {
+            if (x > y)
+            {
+                return -1;
+            }
+            if (x < y)
+            {
+                return 1;
+            }
+
+            return 0;
+        }
+    }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config
new file mode 100644
index 0000000..cc5fd64
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="MSTest.TestAdapter" version="2.1.1" targetFramework="net45" />
+  <package id="MSTest.TestFramework" version="2.1.1" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2c40d81
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Tools.Collections.Concurrent.AsyncBuffer.UnitTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tools.Collections.Concurrent.AsyncBuffer.UnitTest")]
+[assembly: AssemblyCopyright("Copyright ©  2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("3ac3937e-72b5-47fe-bdbe-44f6e4879215")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs
new file mode 100644
index 0000000..8662451
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+    public static class Settings
+    {
+        public static int Count { private set; get; }
+            = 100000;
+    }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs
new file mode 100644
index 0000000..70d94d9
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs
@@ -0,0 +1,57 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+    [TestClass]
+    public class BufferTest
+    {
+        [TestMethod]
+        public void TestConcurrentBuffer()
+        {
+            IConcurrentStore<string> store
+                = new QueueStore<string>();
+            IConcurrentBuffer<string> dataStor
+                = new ConcurrentBuffer<string>(100, store);
+
+            var producerTask = Task.Run(
+                () =>
+                {
+                    for (int i = 0; i < Settings.Count; i++)
+                    {
+                        dataStor.AddForce(i.ToString());
+                    }
+                }
+                );
+
+            var consumerTask = Task.Run(
+                async () =>
+                {
+                    for (int i = 0; i < Settings.Count; i++)
+                    {
+                        await dataStor.ConsumeOrWaitAsync()
+                            .ConfigureAwait(false);
+                    }
+                }
+                );
+
+            Task.WaitAll(
+                producerTask,
+                consumerTask
+                );
+
+            if (dataStor.Size != 0)
+            {
+                throw new Exception();
+            }
+        }
+
+    }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs
new file mode 100644
index 0000000..eb38691
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs
@@ -0,0 +1,132 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+using Tools.Collections.Concurrent.AsyncBuffer.UnitTest.Fake;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+    [TestClass]
+    public class PriorityBufferTest
+    {
+        [TestMethod]
+        public void TestConcurrentBuffer()
+        {
+            IConcurrentStore<string> store
+                = new QueueStore<string>();
+            IConcurrentBuffer<string> dataStor
+                = new ConcurrentBuffer<string>(100, store);
+
+            var producerTask = Task.Run(
+                () =>
+                {
+                    for (int i = 0; i < Settings.Count; i++)
+                    {
+                        dataStor.AddForce(i.ToString());
+                    }
+                }
+                );
+
+            var consumerTask = Task.Run(
+                async () =>
+                {
+                    for (int i = 0; i < Settings.Count; i++)
+                    {
+                        await dataStor.ConsumeOrWaitAsync()
+                            .ConfigureAwait(false);
+                    }
+                }
+                );
+
+            Task.WaitAll(
+                producerTask,
+                consumerTask
+                );
+
+            if (dataStor.Size != 0)
+            {
+                throw new Exception();
+            }
+        }
+
+        [TestMethod]
+        public void TestConcurrentBufferPriorityWrapper2()
+        {
+            EnumTestPrioriry[] priorityValues
+                = (EnumTestPrioriry[])Enum.GetValues(typeof(EnumTestPrioriry));
+
+            if (Settings.Count % priorityValues.Length != 0)
+            {
+                throw new Exception("Count % priorityValues.Length != 0");
+            }
+            var cnt = Settings.Count / priorityValues.Length;
+
+            // Key - приоритет
+            // Value - соответсующее приоритету хранилище
+            var concurrentStores
+                = new SortedDictionary<EnumTestPrioriry, IConcurrentStore<EnumTestPrioriry>>(
+                    priorityValues
+                        .ToDictionary(
+                            e => e,
+                            e => new QueueStore<EnumTestPrioriry>() as IConcurrentStore<EnumTestPrioriry>
+                            ),
+                    new PriorityComparer()
+                    );
+
+            var priorityStore
+                = new ConcurrentStorePriorityWrapper<EnumTestPrioriry, EnumTestPrioriry>(concurrentStores);
+
+            var priorityBuffer
+                = new ConcurrentBufferPriorityWrapper<EnumTestPrioriry, EnumTestPrioriry>(Settings.Count, priorityStore);
+
+
+            foreach (var elem in priorityValues)
+            {
+                for (int i = 0; i < cnt; i++)
+                {
+                    priorityBuffer.AddForce(elem, elem);
+                }
+            }
+
+            foreach (var elem in priorityValues)
+            {
+                if (concurrentStores[elem].Size != cnt)
+                {
+                    throw new Exception("Ошибка заполнения хранилища с приоритетами");
+                }
+            }
+
+            //Проверяем, что порядок извлечения элементов из буфера идет по убыванию за счет PriorityComparer
+            foreach (var elem in priorityValues.OrderByDescending(e => e))
+            {
+                for (int i = 0; i < cnt; i++)
+                {
+                    var consumeResult = priorityBuffer
+                        .ConsumeOrWaitAsync()
+                        .GetAwaiter()
+                        .GetResult();
+
+                    if (consumeResult != elem)
+                    {
+                        throw new Exception($"Неверный порядок приоритета {consumeResult}");
+                    }
+                }
+            }
+
+            if (
+                priorityStore.Size != 0
+                || priorityBuffer.Size != 0
+                )
+            {
+                throw new Exception();
+            }
+        }
+
+    }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs
new file mode 100644
index 0000000..57ff6d7
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs
@@ -0,0 +1,66 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+    [TestClass]
+    public class StoreTest
+    {
+        
+        [TestMethod]
+        public void TestQueueStore()
+        {
+            IConcurrentStore<string> store = new QueueStore<string>();
+
+            for (int i = 0; i < Settings.Count; i++)
+            {
+                store.Add(i.ToString());
+            }
+
+            while (store.Size != 0)
+            {
+                store.TryTake(out string s);
+            }
+        }
+
+        [TestMethod]
+        public void TestStackStore()
+        {
+            IConcurrentStore<string> store = new StackStore<string>();
+
+            for (int i = 0; i < Settings.Count; i++)
+            {
+                store.Add(i.ToString());
+            }
+
+            while (store.Size != 0)
+            {
+                store.TryTake(out string s);
+            }
+        }
+
+        [TestMethod]
+        public void TestBagStore()
+        {
+            IConcurrentStore<string> store = new BagStore<string>();
+
+            for (int i = 0; i < Settings.Count; i++)
+            {
+                store.Add(i.ToString());
+            }
+
+            while (store.Size != 0)
+            {
+                store.TryTake(out string s);
+            }
+        }       
+
+    }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj
new file mode 100644
index 0000000..6faccd5
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{3AC3937E-72B5-47FE-BDBE-44F6E4879215}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Tools.Collections.Concurrent.AsyncBuffer.UnitTest</RootNamespace>
+    <AssemblyName>Tools.Collections.Concurrent.AsyncBuffer.UnitTest</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Fake\EnumTestPrioriry.cs" />
+    <Compile Include="Settings.cs" />
+    <Compile Include="Test\BufferTest.cs" />
+    <Compile Include="Test\PriorityBufferTest.cs" />
+    <Compile Include="Test\StoreTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Tools.Collections.Concurrent.AsyncBuffer\Tools.Collections.Concurrent.AsyncBuffer.csproj">
+      <Project>{97e537c2-2737-46ad-966e-d48e0a93966e}</Project>
+      <Name>Tools.Collections.Concurrent.AsyncBuffer</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их.  Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props'))" />
+    <Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets'))" />
+  </Target>
+  <Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" />
+</Project>
\ No newline at end of file
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs
new file mode 100644
index 0000000..d2be973
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+using Tools.CancellationTokenAsync;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer
+{
+    public class ConcurrentBuffer<T>
+        : IConcurrentBuffer<T>
+    {
+        public int RecommendedMaxSize { private set; get; }
+
+        private readonly IConcurrentStore<T> _Storage;
+
+
+        public int Size
+            => _Storage.Size;
+
+        public ConcurrentBuffer(
+            int recommendedMaxSize, 
+            IConcurrentStore<T> store
+            )
+        {
+            RecommendedMaxSize = recommendedMaxSize;
+            _Storage = store;
+        }
+
+        public void AddForce(T dateEntity)
+        {            
+            _Storage.Add(dateEntity);
+        }
+
+        public bool TryAdd(T dataEntity)
+        {
+            if (Size >= RecommendedMaxSize)
+            {
+                return false;
+            }
+
+            AddForce(dataEntity);
+            return true;
+        }
+
+
+        /// <summary>
+        /// Ожидание поступления нового элемента в хранилище.
+        /// </summary>
+        private async Task WaitUntilNotEmpty(
+            CancellationToken cancellation
+            )
+        {
+            //Если элемент был добавлен в промежутке 
+            if (_Storage.Size != 0)
+            {
+                //то выходим
+                return;
+            }
+
+            var cancellationTokenSource = CancellationTokenSource
+                .CreateLinkedTokenSource(cancellation);
+
+            var token = cancellationTokenSource.Token;
+
+            var taskCompletion 
+                = new TaskCompletionSource<int>();
+
+            using (
+                token.Register(
+                    () => taskCompletion.SetResult(0)
+                )
+                ) 
+            {
+                void StopWait(
+                    IConcurrentStore<T> store,
+                    T item
+                    )
+                {
+                    cancellationTokenSource.Cancel();
+                }
+
+                //Добавляем заявку ожидания нового элемента
+                _Storage.OnItemAdded += StopWait;
+
+                //Если элемент был добавлен в промежутке 
+                if (_Storage.Size != 0)
+                {
+                    //то выходим
+                    return;
+                }
+
+                try
+                {
+                    //Ждем оповещения о поступлении элемента
+                    await taskCompletion
+                        .Task
+                        .ConfigureAwait(false);
+                }
+                finally
+                {
+                    //Удаляем заявку ожидания поступления нового элемента
+                    _Storage.OnItemAdded -= StopWait;
+                }
+            }                
+        }
+
+
+        public async Task<T[]> ConsumeBatchOrWaitAsync(
+            int maxBatchSize,
+            CancellationToken cancellation = default,
+            bool configureAwait = false,
+            bool throwOperationCanceledException = false
+            )
+        {
+            do
+            {
+                //Если удалось получить хотя бы 1 элемент из хранилища
+                if (_Storage.TryTake(out T data))
+                {
+                    List<T> result = new List<T>(maxBatchSize);
+
+                    //То извлекаем пока не пусто или не достигнут maxBatchSize
+                    do
+                    {
+                        result.Add(data);
+                    }
+                    while (
+                        !cancellation.IsCancellationRequested
+                        && result.Count <= maxBatchSize
+                        && _Storage.TryTake(out data)
+                        );
+
+                    return result.ToArray();
+                }
+
+                //хранилище пустое
+
+                //Ждем, пока в хранилище не добавят новый элемент
+                //или сработает cancellation
+                await WaitUntilNotEmpty(cancellation)
+                    .ConfigureAwait(configureAwait);
+            }
+            while (
+                !cancellation.IsCancellationRequested
+                );
+
+            if (throwOperationCanceledException)
+            {
+                cancellation.ThrowIfCancellationRequested();
+            }
+
+            return new T[0];
+        }
+
+        public async Task<T> ConsumeOrWaitAsync(
+            CancellationToken cancellation = default,
+            bool configureAwait = false,
+            bool throwOperationCanceledException = false
+            )
+        {
+            do
+            {
+                //Если удалось получить элемент из хранилища
+                if (_Storage.TryTake(out T data))
+                {
+                    //То берем его
+                    return data;
+                }
+
+                //хранилище пустое
+
+                //Ждем, пока в хранилище не добавят новый элемент
+                //или пока запрос не отменят
+                await WaitUntilNotEmpty(cancellation)
+                        .ConfigureAwait(configureAwait);
+            } while (
+                    !cancellation.IsCancellationRequested
+                    );
+
+            if (throwOperationCanceledException)
+            {
+                cancellation.ThrowIfCancellationRequested();
+            }
+
+            return default;
+        }
+    }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs
new file mode 100644
index 0000000..9f8279d
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer
+{
+    public interface IConcurrentBuffer<T>
+    {
+        /// <summary>
+        /// Рекомендуемый максимальный размер.
+        /// Само хранилище не контролирует размер
+        /// </summary>
+        int RecommendedMaxSize { get; }
+
+        /// <summary>
+        /// Текущий размер коллекции
+        /// </summary>
+        int Size { get; }
+
+        //IConcurrentStore<T> Storage { get; }
+
+        /// <summary>
+        /// Запрашивает группу данных из хранилища для обработки. n - кол-во данных в хранилище.
+        /// Если n = 0, то ожидает поступления данных.
+        /// Если n <= maxBatchSize, то возвращает n записей.
+        /// Если n > maxBatchSize, то возвращает maxBatchSize записей.
+        /// </summary>
+        /// <param name="maxBatchSize">Максимальный размер группы</param>
+        /// <param name="cancellation">Токен, прерывает ожидание новых данных в случае n = 0</param>
+        /// <returns></returns>
+        Task<T[]> ConsumeBatchOrWaitAsync(
+            int maxBatchSize,
+            CancellationToken cancellation = default,
+            bool configureAwait = false,
+            bool throwOperationCanceledException = false
+            );
+
+        /// <summary>
+        /// Извлекает один элемент или ожидает, пока он не появиться или до отмены.
+        /// </summary>
+        Task<T> ConsumeOrWaitAsync(
+            CancellationToken cancellation = default,
+            bool configureAwait = false,
+            bool throwOperationCanceledException = false
+            );
+
+
+        /// <summary>
+        /// Принудительно добавить в хранилище.
+        /// Не проверяет значение RecommendedMaxSize
+        /// </summary>
+        /// <param name="dateEntity"></param>
+        void AddForce(T dateEntity);
+
+        /// <summary>
+        /// Попытка добавить запись в хранилище.
+        /// Запись не будет добавлена, если хранилище заполнено (RecommendedMaxSize).
+        /// При выполнении хранилище не блокируется и значение Size может превысить RecommendedMaxSize. 
+        /// </summary>
+        bool TryAdd(T dataEntity);
+
+    }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs
new file mode 100644
index 0000000..83a31e0
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+    public class ConcurrentBufferPriorityWrapper<T, TPriority>
+        : ConcurrentBuffer<T>,
+        IConcurrentBufferPriorityWrapper<T, TPriority>
+    {
+        private readonly IConcurrentStorePriorityWrapper<T, TPriority> _PriorityStorage;
+
+        public ConcurrentBufferPriorityWrapper(
+            int recommendedMaxSize,
+            IConcurrentStorePriorityWrapper<T, TPriority> storage
+            )
+            : base(recommendedMaxSize, storage)
+        {
+            _PriorityStorage = storage;
+        }
+
+        public void AddForce(T dateEntity, TPriority priority) 
+        {
+            _PriorityStorage.Add(dateEntity, priority);
+        }
+
+        public bool TryAdd(T dataEntity, TPriority priority) 
+        {
+            if (Size >= RecommendedMaxSize)
+            {
+                return false;
+            }
+
+            AddForce(dataEntity, priority);
+            return true;
+        }
+
+    }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs
new file mode 100644
index 0000000..f37813a
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+
+    public class ConcurrentStorePriorityWrapper<T, TPriority>
+        : IConcurrentStorePriorityWrapper<T, TPriority>
+    {
+        public readonly SortedDictionary<TPriority, IConcurrentStore<T>> PriorityStorages;
+
+        private int _Size;
+        public int Size
+            => _Size;
+
+        public event Action<IConcurrentStore<T>, T> OnItemAdded;
+        public event Action<IConcurrentStore<T>> OnEmpty;
+
+        public ConcurrentStorePriorityWrapper(
+            SortedDictionary<TPriority, IConcurrentStore<T>> priorityStorages
+            ) 
+        {
+            _Size = priorityStorages.Sum(e => e.Value.Size);
+            PriorityStorages = priorityStorages;
+        }
+
+        public int Add(T data)
+        {
+            return Add(data, default);
+        }
+        public int Add(T data, TPriority priority)
+        {
+            PriorityStorages[priority].Add(data);
+            Interlocked.Increment(ref _Size);
+            OnItemAdded?.Invoke(this, data);
+            return _Size;
+        }
+
+        public bool TryTake(out T data)
+        {
+            foreach (var elem in PriorityStorages)
+            {
+                if (elem.Value.TryTake(out data))
+                {
+                    Interlocked.Decrement(ref _Size);
+
+                    if (_Size == 0)
+                    {
+                        OnEmpty?.Invoke(this);
+                    }
+
+                    return true;
+                }
+            }
+
+            data = default;
+            return false;
+        }
+        public bool TryTake(out T data, TPriority priority)
+        {
+            if (PriorityStorages[priority].TryTake(out data))
+            {
+                Interlocked.Decrement(ref _Size);
+
+                if (_Size == 0)
+                {
+                    OnEmpty?.Invoke(this);
+                }
+
+                return true;
+            }
+
+            data = default;
+            return false;
+        }
+
+
+        public IEnumerable<T> AsIEnumerable()
+        {
+            return PriorityStorages
+                .Values
+                .SelectMany(e => e.AsIEnumerable());
+        }
+
+        public void ForEach(Action<T> action)
+        {
+            foreach (var elem in PriorityStorages)
+            {
+                elem.Value.ForEach(action);
+            }
+        }
+
+        public IReadOnlyDictionary<TPriority, IConcurrentStore<T>> AsDictionary() 
+        {
+            return PriorityStorages
+                as IReadOnlyDictionary<TPriority, IConcurrentStore<T>>;
+        }      
+    }
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs
new file mode 100644
index 0000000..c453c05
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+    public interface IConcurrentBufferPriorityWrapper<T, TPriority>
+        : IConcurrentBuffer<T>
+    {
+        /// <summary>
+        /// Принудительно добавить в хранилище.
+        /// Не проверяет значение RecommendedMaxSize
+        /// </summary>
+        /// <param name="dateEntity"></param>
+        void AddForce(T dateEntity, TPriority priority);
+
+        /// <summary>
+        /// Попытка добавить запись в хранилище.
+        /// Запись не будет добавлена, если хранилище заполнено (RecommendedMaxSize).
+        /// При выполнении хранилище не блокируется, и значение Size может превысить RecommendedMaxSize. 
+        /// </summary>
+        bool TryAdd(T dataEntity, TPriority priority);
+
+    }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs
new file mode 100644
index 0000000..872686b
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+
+    public interface IConcurrentStorePriorityWrapper<T, TPriority>
+        : IConcurrentStore<T>
+    {
+        int Add(T data, TPriority priority);
+
+        bool TryTake(out T data, TPriority priority);
+
+        IReadOnlyDictionary<TPriority, IConcurrentStore<T>> AsDictionary();
+    }
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f279ed4
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Общие сведения об этой сборке предоставляются следующим набором
+// набора атрибутов. Измените значения этих атрибутов для изменения сведений,
+// связанные со сборкой.
+[assembly: AssemblyTitle("Tools.Collections.Concurrent.AsyncBuffer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tools.Collections.Concurrent.AsyncBuffer")]
+[assembly: AssemblyCopyright("Copyright ©  2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
+// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
+// COM, задайте атрибуту ComVisible значение TRUE для этого типа.
+[assembly: ComVisible(false)]
+
+// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
+[assembly: Guid("97e537c2-2737-46ad-966e-d48e0a93966e")]
+
+// Сведения о версии сборки состоят из указанных ниже четырех значений:
+//
+//      Основной номер версии
+//      Дополнительный номер версии
+//      Номер сборки
+//      Редакция
+//
+// Можно задать все значения или принять номера сборки и редакции по умолчанию 
+// используя "*", как показано ниже:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs
new file mode 100644
index 0000000..7266b0c
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+    public class BagStore<T>
+        : IConcurrentStore<T>
+    {
+        private readonly ConcurrentBag<T> Storage
+            = new ConcurrentBag<T>();
+
+        private int _Size;
+
+        public event Action<IConcurrentStore<T>, T> OnItemAdded;
+        public event Action<IConcurrentStore<T>> OnEmpty;
+
+        public int Size
+            => _Size;
+
+        public int Add(T data)
+        {
+            Storage.Add(data);
+            Interlocked.Increment(ref _Size);
+            OnItemAdded?.Invoke(this, data);
+
+            return _Size;
+        }
+        public bool TryTake(out T data)
+        {
+            if (Storage.TryTake(out data))
+            {
+                Interlocked.Decrement(ref _Size);
+
+                if (_Size == 0)
+                {
+                    OnEmpty?.Invoke(this);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        public IEnumerable<T> AsIEnumerable()
+        {
+            return Storage;
+        }
+
+        public void ForEach(Action<T> action)
+        {
+            foreach (var elem in Storage)
+            {
+                action(elem);
+            }
+        }
+    }
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs
new file mode 100644
index 0000000..ae016fd
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+    public interface IConcurrentStore<T>
+    {
+        int Size { get; }
+
+        int Add(T data);
+        bool TryTake(out T data);
+
+        IEnumerable<T> AsIEnumerable();
+        void ForEach(Action<T> action);
+
+
+        /// <summary>
+        /// В хранилище добавлен новый элемент.
+        /// </summary>
+        event Action<IConcurrentStore<T>, T> OnItemAdded;
+
+        /// <summary>
+        /// Хранилище опустело.
+        /// </summary>
+        event Action<IConcurrentStore<T>> OnEmpty;
+
+    }
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs
new file mode 100644
index 0000000..0a94912
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+    public class QueueStore<T>
+        : IConcurrentStore<T>
+    {
+        public readonly ConcurrentQueue<T> Storage 
+            = new ConcurrentQueue<T>();
+
+        private int _Size;
+        public int Size
+            => _Size;
+
+        public event Action<IConcurrentStore<T>, T> OnItemAdded;
+        public event Action<IConcurrentStore<T>> OnEmpty;
+
+        public int Add(T data)
+        {
+            Storage.Enqueue(data);
+            Interlocked.Increment(ref _Size);
+            OnItemAdded?.Invoke(this, data);
+
+            return _Size;
+        }
+
+        public bool TryTake(out T data)
+        {
+            if (Storage.TryDequeue(out data)) 
+            {
+                Interlocked.Decrement(ref _Size);
+
+                if (_Size == 0)
+                {
+                    OnEmpty?.Invoke(this);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        public IEnumerable<T> AsIEnumerable()
+        {
+            return Storage;
+        }
+        public void ForEach(Action<T> action)
+        {
+            foreach (var elem in Storage)
+            {
+                action(elem);
+            }
+        }
+    }    
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs
new file mode 100644
index 0000000..9c9ba93
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+    public class StackStore<T>
+        : IConcurrentStore<T>
+    {
+        private readonly ConcurrentStack<T> Storage
+            = new ConcurrentStack<T>();
+
+        private int _Size;
+
+        public event Action<IConcurrentStore<T>, T> OnItemAdded;
+        public event Action<IConcurrentStore<T>> OnEmpty;
+
+        public int Size
+            => _Size;
+
+        public int Add(T data)
+        {
+            Storage.Push(data);
+            Interlocked.Increment(ref _Size);
+            OnItemAdded?.Invoke(this, data);
+
+            return _Size;
+        }
+
+        public bool TryTake(out T data)
+        {
+            if (Storage.TryPop(out data))
+            {
+                Interlocked.Decrement(ref _Size);
+
+                if (_Size == 0)
+                {
+                    OnEmpty?.Invoke(this);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        public IEnumerable<T> AsIEnumerable()
+        {
+            return Storage;
+        }
+
+        public void ForEach(Action<T> action)
+        {
+            foreach (var elem in Storage)
+            {
+                action(elem);
+            }
+        }
+    }
+
+    
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj
new file mode 100644
index 0000000..c3ff244
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{97E537C2-2737-46AD-966E-D48E0A93966E}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Tools.Collections.Concurrent.AsyncBuffer</RootNamespace>
+    <AssemblyName>Tools.Collections.Concurrent.AsyncBuffer</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ConcurrentBuffer.cs" />
+    <Compile Include="IConcurrentBuffer.cs" />
+    <Compile Include="PriorityWrapper\ConcurrentStorePriorityWrapper.cs" />
+    <Compile Include="PriorityWrapper\ConcurrentBufferPriorityWrapper.cs" />
+    <Compile Include="Store\StackStore.cs" />
+    <Compile Include="Store\BagStore.cs" />
+    <Compile Include="Store\QueueStore.cs" />
+    <Compile Include="Store\IConcurrentStore.cs" />
+    <Compile Include="PriorityWrapper\IConcurrentBufferPriorityWrapper.cs" />
+    <Compile Include="PriorityWrapper\IConcurrentStorePriorityWrapper.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Tools.CancellationTokenAsync\Tools.CancellationTokenAsync.csproj">
+      <Project>{f1de016d-9ac4-4d10-a89a-0142a424c3ad}</Project>
+      <Name>Tools.CancellationTokenAsync</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file
diff --git a/src/Tools.Collections/Tools.Collections.sln b/src/Tools.Collections/Tools.Collections.sln
index 72e2819..637e8d1 100644
--- a/src/Tools.Collections/Tools.Collections.sln
+++ b/src/Tools.Collections/Tools.Collections.sln
@@ -9,13 +9,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{E674A5DB-8D7
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{4762CF50-BA4B-443A-954A-803E4CEF6451}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.Extensions", "Tools.Collections.ConcurrentDictonary.Extensions\Tools.Collections.Concurrent.Extensions.csproj", "{7531E7FD-16D7-4111-8FBD-D98F23D7C53C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.Extensions", "Tools.Collections.ConcurrentDictonary.Extensions\Tools.Collections.Concurrent.Extensions.csproj", "{7531E7FD-16D7-4111-8FBD-D98F23D7C53C}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.SortedDictionarySortKeyItemKey", "Tools.Collections.SortedDictionarySortKeyItemKey\Tools.Collections.SortedDictionarySortKeyItemKey.csproj", "{83C77E76-7114-4494-A7D3-6B4D54767AC6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.SortedDictionarySortKeyItemKey", "Tools.Collections.SortedDictionarySortKeyItemKey\Tools.Collections.SortedDictionarySortKeyItemKey.csproj", "{83C77E76-7114-4494-A7D3-6B4D54767AC6}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.LinkItemDictionary", "Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj", "{E221963A-526E-43C1-A6D5-BF4D9721BC59}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.LinkItemDictionary", "Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj", "{E221963A-526E-43C1-A6D5-BF4D9721BC59}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.ObjectLinkItemDictionary", "Tools.Collections.ObjectLinkItemDictionary\Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj", "{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.ObjectLinkItemDictionary", "Tools.Collections.ObjectLinkItemDictionary\Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj", "{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.AsyncBuffer", "Tools.Collections.Concurrent.AsyncBuffer\Tools.Collections.Concurrent.AsyncBuffer.csproj", "{97E537C2-2737-46AD-966E-D48E0A93966E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.AsyncBuffer.UnitTest", "Tools.Collections.Concurrent.AsyncBuffer.UnitTest\Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj", "{3AC3937E-72B5-47FE-BDBE-44F6E4879215}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -43,6 +47,14 @@ Global
 		{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{97E537C2-2737-46AD-966E-D48E0A93966E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{97E537C2-2737-46AD-966E-D48E0A93966E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{97E537C2-2737-46AD-966E-D48E0A93966E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{97E537C2-2737-46AD-966E-D48E0A93966E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -53,6 +65,8 @@ Global
 		{83C77E76-7114-4494-A7D3-6B4D54767AC6} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
 		{E221963A-526E-43C1-A6D5-BF4D9721BC59} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
 		{0792B9B8-BBB9-4421-81A1-A534B43CA6B8} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+		{97E537C2-2737-46AD-966E-D48E0A93966E} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+		{3AC3937E-72B5-47FE-BDBE-44F6E4879215} = {4762CF50-BA4B-443A-954A-803E4CEF6451}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {C32931BC-9551-4A06-9A76-F7E4F162B3C7}