Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.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#_.net_Multithreading_Thread Safety - Fatal编程技术网

C# 为什么这些次线程不结束它们的执行?

C# 为什么这些次线程不结束它们的执行?,c#,.net,multithreading,thread-safety,C#,.net,Multithreading,Thread Safety,我正在创建一个控制台应用程序,它应该接收来自网络的消息,以便处理它们。首先,我创建了一个单例类,以确保所有类都可以访问相同的队列:这个类是ProcessingQueue public class ProcessingQueue { public class ItemToProcess { public string SourceClientId { get; set; } public IMessage ReceivedMessage { get;

我正在创建一个控制台应用程序,它应该接收来自网络的消息,以便处理它们。首先,我创建了一个单例类,以确保所有类都可以访问相同的队列:这个类是
ProcessingQueue

public class ProcessingQueue
{
    public class ItemToProcess
    {
        public string SourceClientId { get; set; }
        public IMessage ReceivedMessage { get; set; }
    }

    private int m_MaxSize = 20;
    private Queue<ItemToProcess> m_InternalQueue;

    private static volatile ProcessingQueue m_Instance = null;
    private static readonly object syncRoot = new object();

    private ProcessingQueue()
    {
        m_InternalQueue = new Queue<ItemToProcess>();
    }

    public static ProcessingQueue Instance
    {
        get
        {
            if (m_Instance == null)
            {
                lock (syncRoot)
                {
                    if (m_Instance == null)
                    {
                        m_Instance = new ProcessingQueue();
                    }
                }
            }
            return m_Instance;
        }
    }

    public int MaxSize
    {
        get
        {
            lock (syncRoot)
            {
                return m_MaxSize;
            }
        }
        set
        {
            if (value > 0)
            {
                lock (syncRoot)
                {
                    m_MaxSize = value;
                }
            }
        }
    }

    public void Enqueue(String source, IMessage message)
    {
        lock (syncRoot)
        {
            while (m_InternalQueue.Count >= m_MaxSize)
            {
                Monitor.Wait(syncRoot);
            }
            m_InternalQueue.Enqueue(new ItemToProcess { SourceClientId = source, ReceivedMessage = message });
            if (m_InternalQueue.Count == 1)
            {
                Monitor.PulseAll(syncRoot);
            }
        }
    }

    public ItemToProcess Dequeue()
    {
        lock (syncRoot)
        {
            while (m_InternalQueue.Count == 0)
            {
                Monitor.Wait(syncRoot);
            }
            ItemToProcess item = m_InternalQueue.Dequeue();
            if (m_InternalQueue.Count == m_MaxSize - 1)
            {
                Monitor.PulseAll(syncRoot);
            }
            return item;
        }
    }

    public int Count
    {
        get
        {
            lock (syncRoot)
            {
                return m_InternalQueue.Count;
            }
        }
    }
}
}

在执行过程中按Enter键,
running
变量变为false,两个线程都应该终止。然而,这并不总是发生,事实上,两个方法
Join
中的一个没有返回控件:因此,我在
Join
方法中指定了一个超时,但在
Console.WriteLine(“END”)之后
控制台应用程序冻结(第二个
连接
返回


可能第二个线程没有正确终止。。。为什么?

似乎出列或排队可以进入
监视器。Wait()
,当停止运行时,没有人脉冲

等待5秒,但请注意MaxSize*1500>5000


我无法直接找出计时器的频率

使用
Lazy
实现单例模式要容易得多,但我一直认为单例模式是最粗糙的模式。好的,但我需要一个WCF服务实例可以访问的队列:在我的代码中,我模拟了来自网络的数据,但实际上,WCF服务的许多实例必须将数据放入队列中。我可以只更改
Join
方法中的等待时间吗?或者我也应该使用更简单的方法而不是
监视器
?您的入/出队列方法根本没有停止逻辑。。。只需使用一个library类。你所说的library类是什么意思?我应该使用类作为
ConcurrentQueue
private static volatile bool running = true;


static void Main(string[] args)
{
    queue.MaxSize = 30;
    keep_alive_timer.Elapsed += new ElapsedEventHandler(delegate(object sender, ElapsedEventArgs e)
    {
        KeepAliveMessage msg = new KeepAliveMessage(Guid.NewGuid());
        Console.WriteLine("Keep Alive: " + msg.MsgId);
        queue.Enqueue("", msg);
    });
    keep_alive_timer.Enabled = true;
    keep_alive_timer.AutoReset = true;

    Thread processing = new Thread(delegate()
    {
        while (running)
        {
            Console.WriteLine("Number of elements in queue: {0}", queue.Count);

            ProcessingQueue.ItemToProcess msg = queue.Dequeue();
            Console.WriteLine("Processed: msgid={0}, source={1};", msg.ReceivedMessage.MsgId, msg.SourceClientId);

            Thread.Sleep(1500);
        }
    });

    Thread generating = new Thread(MessagesFromNetwork);

    processing.Start();
    keep_alive_timer.Start();
    generating.Start();

    Console.WriteLine("RUNNING...\n");
    Console.ReadLine();

    running = false;
    keep_alive_timer.Stop();
    Console.WriteLine("CLOSING...\n");

    //processing.Abort();
    //generating.Abort();

    bool b1 = processing.Join(TimeSpan.FromSeconds(5));
    bool b2 = generating.Join(TimeSpan.FromSeconds(5));

    Console.WriteLine("b1 {0}", b1);
    Console.WriteLine("b2 {0}", b2);
    Console.WriteLine("END");
    Console.ReadLine();
}

static void MessagesFromNetwork()
{
    string[] sourceClients = { "1", "2", "3", "4", "5" };
    while (running)
    {
        IMessage msg; // interface IMessage
        Random random = new Random();
        int type = random.Next(2);
        switch (type)
        {
            case 0:
                msg = new KeepAliveMessage(Guid.NewGuid());   // implements IMessage
                break;
            case 1:
                msg = new TaskMessage(Guid.NewGuid(), ...);   // implements IMessage
                break;
            default:
                throw new Exception("Messaggio non valido!");
        }
        Console.WriteLine("New message received: " + msg.MsgId);
        queue.Enqueue(sourceClients[random.Next(sourceClients.Length)], msg);
        Console.WriteLine("... message enqueued: " + msg.MsgId);
        Thread.Sleep(500);
    }
}