多线程:如何检查静态类是否繁忙

时间:2017-05-24 21:56:29

标签: c# multithreading locking

我有一个静态类,它有一个静态函数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;
    }
}

2 个答案:

答案 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();
    }
}