Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 排队失败_C#_Multithreading_Queue - Fatal编程技术网

C# 排队失败

C# 排队失败,c#,multithreading,queue,C#,Multithreading,Queue,我有一个简单的日志机制,应该是线程安全的。它在大多数情况下都能工作,但我偶尔会在这一行上遇到一个例外,“_logQ.Enqueue(s);”队列不够长。在调试器中,有时只有数百个项目,所以我看不到它是资源。队列应该根据需要扩展。如果捕获异常而不是让调试器在异常处暂停,则会看到相同的错误。这里有线程不安全的东西吗?我甚至不知道如何开始调试这个 static void ProcessLogQ(object state) { try {

我有一个简单的日志机制,应该是线程安全的。它在大多数情况下都能工作,但我偶尔会在这一行上遇到一个例外,“_logQ.Enqueue(s);”队列不够长。在调试器中,有时只有数百个项目,所以我看不到它是资源。队列应该根据需要扩展。如果捕获异常而不是让调试器在异常处暂停,则会看到相同的错误。这里有线程不安全的东西吗?我甚至不知道如何开始调试这个

    static void ProcessLogQ(object state)
    {
        try
        {
            while (_logQ.Count > 0)
            {
                var s = _logQ.Dequeue();
                string dir="";
                Type t=Type.GetType("Mono.Runtime");
                if (t!=null)
                {
                    dir ="/var/log";
                }else
                {
                    dir = @"c:\log";
                    if (!Directory.Exists(dir))
                        Directory.CreateDirectory(dir);
                }
                if (Directory.Exists(dir))
                {
                    File.AppendAllText(Path.Combine(dir, "admin.log"), DateTime.Now.ToString("hh:mm:ss ") + s + Environment.NewLine);
                }
            }
        }
        catch (Exception)
        {
        }
        finally
        {
            _isProcessingLogQ = false;
        }
    }

    public static void Log(string s) {
        if (_logQ == null)
            _logQ = new Queue<string> { };

        lock (_logQ)
            _logQ.Enqueue(s);
        if (!_isProcessingLogQ) {
            _isProcessingLogQ = true;
            ThreadPool.QueueUserWorkItem(ProcessLogQ);
        }
    }

对于线程安全队列,应改用ConcurrentQueue:


查看TaskParallel库。所有的艰苦工作都已经为你完成了。如果您这样做是为了了解多线程,请阅读锁定技术以及每种技术的优缺点

此外,您正在检查lock语句之外的_logQ是否为null,根据我可以推断,这是一个静态字段,您没有在静态构造函数中初始化它。您可以避免执行这种空检查(它应该在锁中,这是关键代码!),您可以通过将其设置为静态只读并在静态构造函数中初始化来确保线程安全

此外,您没有正确处理队列状态。由于在检查队列计数期间没有锁定,因此每次迭代时都可能发生变化。您在退出队列时丢失了一个锁

优秀资源:

有什么理由反对投票吗?我研究了这个话题,也知道该怎么做,把所有的信息都很清楚地放在一起。我们是不是应该成为提问的专家。。。所以在这种情况下,我们就不需要问了?如果你在循环中退出队列,为什么要使用线程?您实际上可以创建一个使用实例的类,并使用更干净的代码来解决这个问题。@CoffeeMuncher,有多个线程将消息放入队列中,日志线程必须位于自己的线程中,这样其他线程就不会被阻塞。这是多线程的经典案例。顺便说一句,我已经解决了这个问题,而且效果很好。我创建了自己的ConcurrentQueue。它必须是自己的线程,这很好,但为了简单和干净,我的观点是,您不必将所有内容都作为静态对象。在循环中处理时放置锁仍然会阻止其他线程写入,这就是锁的要点,您希望捕获处于给定状态的队列,以便对其进行操作。你真正想看到的是生产者…消费者model@CoffeeMuncher,好的,现在我明白你的意思了。它是静态的,因为它在所有用于日志记录的代码中都使用,所以我们不希望每次都实例化一个对象。我想我应该再次发布,或者更新我的解决方案,这样我们就可以回顾我现在实际做的事情。我想听听你对实际解决方案的意见。这里贴的是当我真的不知道自己在做什么的时候(问题的重点)。我想我现在知道的更多了,但你永远不知道你不知道的为了清楚起见,上面的“编辑”还不是最后一个。谢谢你提供的信息。我忘了提到我有一个.NET3.5的限制。我发布了一个编辑更新,我认为它是.NET3.5环境中一个有效的线程安全解决方案。
    static void ProcessLogQ()
    {
        while (true) {
            try {
                lock (_logQ);
                while (_logQ.Count > 0) {
                    var s = _logQ.Dequeue ();
                    string dir = "../../log";
                    if (!Directory.Exists (dir))
                        Directory.CreateDirectory (dir);
                    if (Directory.Exists (dir)) {
                        File.AppendAllText (Path.Combine (dir, "s3ol.log"), DateTime.Now.ToString ("hh:mm:ss ") + s + Environment.NewLine);
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine (ex.Message);
            } finally {
            }
            Thread.Sleep (1000);
        }
    }

    public static void startLogger(){
        lock (t) {
            if (t.ThreadState != ThreadState.Running)
                t.Start ();
        }
    }
    private static void multiThreadLog(string msg){
        lock (_logQ)
            _logQ.Enqueue(msg);
    }