我需要在C#中编写自己的FIFO /强信号量,使用我自己的信号量作为基础。我发现this example,但它不太对,因为我不应该使用Monitor.Enter / Exit。
这些是我的常规信号量的方法,我想知道是否有一种简单的方法可以使它适应FIFO。
public virtual void Acquire()
{
lock (this)
{
while (uintTokens == 0)
{
Monitor.Wait(this);
}
uintTokens--;
}
}
public virtual void Release(uint tokens = 1)
{
lock (this)
{
uintTokens += tokens;
Monitor.PulseAll(this);
}
}
答案 0 :(得分:15)
所以SemaphoreSlim
为我们提供了一个良好的起点,所以我们首先将其中一个包装在一个新类中,然后将等待方法中的所有内容指向该信号量。
要获得类似行为的队列,我们需要一个队列对象,并确保在面对多线程访问时它是安全的,我们将使用ConcurrentQueue
<。 / p>
在此队列中,我们会放置TaskCompletionSource
个对象。当我们想要开始等待时,它可以创建一个TCS,将其添加到队列中,然后通知信号量异步地弹出队列中的下一个项目并将其标记为&#34;已完成&#34;等待结束时我们知道队列中的项目总会有相同或更少的延续。
然后我们等待来自TCS的Task
。
我们还可以简单地创建一个返回任务的WaitAsync
方法,只需返回它而不是等待它。
public class SemaphoreQueue
{
private SemaphoreSlim semaphore;
private ConcurrentQueue<TaskCompletionSource<bool>> queue =
new ConcurrentQueue<TaskCompletionSource<bool>>();
public SemaphoreQueue(int initialCount)
{
semaphore = new SemaphoreSlim(initialCount);
}
public SemaphoreQueue(int initialCount, int maxCount)
{
semaphore = new SemaphoreSlim(initialCount, maxCount);
}
public void Wait()
{
WaitAsync().Wait();
}
public Task WaitAsync()
{
var tcs = new TaskCompletionSource<bool>();
queue.Enqueue(tcs);
semaphore.WaitAsync().ContinueWith(t =>
{
TaskCompletionSource<bool> popped;
if (queue.TryDequeue(out popped))
popped.SetResult(true);
});
return tcs.Task;
}
public void Release()
{
semaphore.Release();
}
}
答案 1 :(得分:0)
我已经创建了FifoSemaphore类,并且已经在我的解决方案中成功使用了它。当前的限制是它的行为类似于Semaphore(1,1)。
$q = "SELECT GROUP_CONCAT(DISTINCT
CONCAT('MAX(CASE WHEN `date` = ''', `date`,
''' THEN `close` END) `', `date`, '`')
ORDER BY YEAR(`date`), MONTH(`date`)
)
INTO @sql
FROM
(SELECT symbol, `date`, `close`
FROM history where `date` IN
(SELECT MAX(`date`) as max_date
FROM history
WHERE date BETWEEN '1998-01-01' AND '2018-12-31' AND symbol = 'QQQ'
GROUP BY YEAR(`date`) )
) a;
SET @sql = CONCAT('SELECT symbol, ', @sql, '
FROM history
GROUP BY symbol');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;";
$stmt = $this->mysqli->prepare($q);
$stmt->execute();
用法就像使用常规信号灯一样:
public Dictionary<Type, List<object>> FindDbContextsInAssemblies()
{
var dbContexts = new Dictionary<Type, List<object>>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach(var assembly in assemblies)
{
foreach(var type in assembly.GetTypes())
{
if(type.IsSubclassOf(typeof(DbContext)))
{
// Instantiate DbContext:
var context = type.GetConstructor(Array.Empty<Type>()).Invoke(Array.Empty<object>());
// Find method to get entities:
var model = type.GetProperty("Model");
var searchMethod = model.PropertyType.GetMethod("GetEntityTypes");
// Get registered entities:
var entities = searchMethod.Invoke(model.GetValue(context, null), null) as List<object>;
dbContexts[type] = entities;
}
}
}
return dbContexts;
}
在每个线程上:
public class FifoSemaphore
{
private readonly object lockObj = new object();
private List<Semaphore> WaitingQueue = new List<Semaphore>();
private Semaphore RequestNewSemaphore()
{
lock (lockObj)
{
Semaphore newSemaphore = new Semaphore(1, 1);
newSemaphore.WaitOne();
return newSemaphore;
}
}
#region Public Functions
public void Release()
{
lock (lockObj)
{
WaitingQueue.RemoveAt(0);
if (WaitingQueue.Count > 0)
{
WaitingQueue[0].Release();
}
}
}
public void WaitOne()
{
Semaphore semaphore = RequestNewSemaphore();
lock (lockObj)
{
WaitingQueue.Add(semaphore);
semaphore.Release();
if(WaitingQueue.Count > 1)
{
semaphore.WaitOne();
}
}
semaphore.WaitOne();
}
#endregion
}