我有一个静态类,它有一个静态函数IsDataCorrect()来执行http请求。
该函数可以同时从多个线程调用,我想让第一个线程执行请求,其他的应该被拒绝(这意味着它们应该作为返回值得到假,它们不应该被阻止!)在第一个线程完成请求后半秒钟。
在那之后,下一个获胜线程应该能够做下一个请求,其他人应该被拒绝,等等。
这是我的方法,有人可以确认这是否合理:
static class MyClass
{
private static bool IsBusy = false;
private static object lockObject = new object();
public static bool IsDataCorrect(string testString)
{
lock (lockObject)
{
if (IsBusy) return false;
IsBusy = true;
}
var uri = $"https://something.com";
bool htmlCheck = GetDocFromUri(uri, 2);
var t = new Thread(WaitBeforeFree);
t.Start();
//Fast Evaluations
//...
return htmlCheck;
}
private static void WaitBeforeFree()
{
Thread.Sleep(500);
IsBusy = false;
}
}
答案 0 :(得分:1)
访问该函数的线程仍会在访问中被序列化以检查IsBusy
标志,因为由于lockObject
上的同步,一次只能有一个线程检查它。相反,您可以简单地尝试获取锁定,因此,您不需要标记,因为锁本身将用作锁定。其次,我每次只是为了睡眠而重置启动新线程并重置标志,并用DateTime
字段上的检查替换它。
static class MyClass
{
private static DateTime NextEntry = DateTime.Now;
private static ReaderWriterLockSlim timeLock = new ReaderWriterLockSlim();
private static object lockObject = new object();
public static bool IsDataCorrect(string testString)
{
bool tryEnterSuccess = false;
try
{
try
{
timeLock.EnterReadLock()
if (DateTime.Now < NextEntry) return false;
}
finally
{
timeLock.ExitReadLock()
}
Monitor.TryEnter(lockObject, ref tryEnterSuccess);
if (!tryEnterSuccess) return false;
var uri = $"https://something.com";
bool htmlCheck = GetDocFromUri(uri, 2);
//Fast Evaluations
//...
try
{
timeLock.EnterWriteLock()
NextEntry = DateTime.Now.AddMilliseconds(500);
} finally {
timeLock.ExitWriteLock()
}
return htmlCheck;
} finally {
if (tryEnterSuccess) Monitor.Exit(lockObject);
}
}
}
这种方式对于不启动新线程的效率更高,DateTime访问是安全的并且是并发的,因此线程仅在绝对必须时停止。否则,一切都在不断移动,资源使用最少。
答案 1 :(得分:1)
我看到你们正确地解决了这个问题,但我认为仍然有空间让它在同一时间正确,高效和简单:)。 这样怎么样?
编辑:编辑以使平静变得更容易,并且是示例的一部分。
public static class ConcurrentCoordinationExtension
{
private static int _executing = 0;
public static bool TryExecuteSequentially(this Action actionToExecute)
{
// compate _executing with zero, if zero, set 1,
// return original value as result,
// successfull entry then result is zero, non zero returned, then somebody is executing
if (Interlocked.CompareExchange(ref _executing, 1, 0) != 0) return false;
try
{
actionToExecute.Invoke();
return true;
}
finally
{
Interlocked.Exchange(ref _executing, 0);//
}
}
public static bool TryExecuteSequentially(this Func<bool> actionToExecute)
{
// compate _executing with zero, if zero, set 1,
// return original value as result,
// successfull entry then result is zero, non zero returned, then somebody is executing
if (Interlocked.CompareExchange(ref _executing, 1, 0) != 0) return false;
try
{
return actionToExecute.Invoke();
}
finally
{
Interlocked.Exchange(ref _executing, 0);//
}
}
}
class Program
{
static void Main(string[] args)
{
DateTime last = DateTime.MinValue;
Func<bool> operation= () =>
{
//calming condition was not meant
if (DateTime.UtcNow - last < TimeSpan.FromMilliseconds(500)) return false;
last = DateTime.UtcNow;
//some stuff you want to process sequentially
return true;
};
operation.TryExecuteSequentially();
}
}