Дано: Library, FW3.5-4.8/STD 2.0 и нулевой опыт многопоточного программирования под .NET
Решил добавить в неё кэш с ранее созданными объектами.
Если быть точнее, то это словарь [connectionString]->[объект connectionOptions].
И хочется прикрутить к этому словарю фоновую зачистку устаревших элементов.
Схема проста.
Поток пользователя
Блокирует словарь
{
Запускает сборщик мусора (или не даем ему завершиться)
Добавляет в словарь
}
Сборщик мусора
for(;;)
{
Блокирует словарь
{
Удаляет устаревшие элементы
Если словарь стал пустым, то завершаем работу
}
Sleep(1 сек)
}
Вопрос насчет выбора механизма для сборщика мусора.
Основные опасения — как этот фоновый сборщик мусора будет себя вести при завершении работы?
--- 1.
Сразу подумал про
Thread+Sleep. Но решил пока не с ним связываться. Наверное это слишком дубовый способ.
--- 2.
Замутил тестовое приложение с использованием
Timer.
Основная проблема — метод сборщика мусора может вызваться до завершения предыдущего вызова. Не очень красиво.
| Если интересно, то вот тестовый код |
| using System;
using System.Threading;
namespace ConsoleApp1{
////////////////////////////////////////////////////////////////////////////////
//class Program
class Program
{
static object sm_LogGuard=new object();
static object sm_Resource__Guard=new object();
static int sm_Resource__Counter=0;
static System.Threading.Timer sm_Resource__GC_Timer=null;
//-------------------------------------------------
static void Main(string[] args)
{
const string c_src="main";
const int c_counter_init=9;
for(int n0=0;n0!=10;++n0)
{
for(int n=0;n!=4;++n)
{
Helper__Log(c_src,"------------------ n: {0}",n);
lock(sm_Resource__Guard)
{
if(sm_Resource__GC_Timer==null)
{
Helper__Log(c_src,"setup timer");
sm_Resource__GC_Timer=new Timer(Resource_GC,null,0,1*1000);
}
if(sm_Resource__Counter==0)
{
Helper__Log(c_src,"set to {0}",c_counter_init);
Interlocked.Exchange(ref sm_Resource__Counter,c_counter_init);
}
else
{
int x=Interlocked.Increment(ref sm_Resource__Counter);
Helper__Log(c_src,"increment to {0}",x);
}//else
}//lock
Thread.Sleep(2*1000);
}//for n
Helper__Log(c_src,"RESET");
var t=Interlocked.Exchange(ref sm_Resource__GC_Timer,null);
if(t!=null)
t.Dispose();
}//for[ever]
Helper__Log(c_src,"EXIT");
}//main
//----------------------------------------------------------------------
static void Resource_GC(object a)
{
string c_src=string.Format("GC_{0}",Thread.CurrentThread.ManagedThreadId);
for(uint n=0;;)
{
++n;
lock(sm_Resource__Guard)
{
if(sm_Resource__Counter==0)
{
var t=Interlocked.Exchange(ref sm_Resource__GC_Timer,null);
if(t==null)
{
Helper__Log(c_src,"Stop [ACHTUNG]!");
}
else
{
Helper__Log(c_src,"Stop GC");
t.Dispose();
}//if
return;
}
if(n>3)
{
Helper__Log(c_src,"Exit");
return;
}
var c=Interlocked.Decrement(ref sm_Resource__Counter);
Helper__Log(c_src,"decrement to {0}",c);
}//lock
}//for[ever]
}//Resource_GC
//----------------------------------------------------------------------
static void Helper__Log(string src,string format,params object[] p)
{
string msg=string.Format(format,p);
lock(sm_LogGuard)
{
Console.WriteLine("[{0}][Thr {1}] {2}",DateTime.Now,src,msg);
}
}//Helper__Log
}//class Program
////////////////////////////////////////////////////////////////////////////////
}
|
| |
--- 3.
"Слышал", что есть такая штука как
Task....
-------------
Кто-нибуль может показать простой/надежный/правильный код для этой задачи?
Или не париться и заюзать Thread+Sleep?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --