Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.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
Multithreading 异步网络条件_Multithreading_Networking_Asynchronous_Synchronization_Race Condition - Fatal编程技术网

Multithreading 异步网络条件

Multithreading 异步网络条件,multithreading,networking,asynchronous,synchronization,race-condition,Multithreading,Networking,Asynchronous,Synchronization,Race Condition,我正在为一个网络应用程序编写一个客户端,我想将消息的接收和处理分离到不同的线程 这是我目前的解决方案: Mutex mutex; Queue queue; recv() { while(true) { messages = receive_some_messages(); mutex.lock(); queue.add(messages); mutex.unlock(); process.not

我正在为一个网络应用程序编写一个客户端,我想将消息的接收和处理分离到不同的线程

这是我目前的解决方案:

Mutex mutex;
Queue queue;

recv()
{
    while(true)
    {
        messages = receive_some_messages();

        mutex.lock();
        queue.add(messages);
        mutex.unlock();

        process.notify();
    }
}

proc()
{
    while(true)
    {
        block_until_notify();
        Queue to_process;

        mutex.lock();
        to_process.add( queue.take_all() );
        mutex.unlock();

        foreach(message in to_process)
        {
            process_message(message);
        }

    }
}
但是,这有一个竞争条件:

  • recv接收大量消息并将它们放入队列
  • 记录通知程序
  • proc从队列中获取所有消息并开始工作
  • recv接收更多消息并将它们放入队列
  • recv通知proc,但由于proc仍在工作,因此不会执行任何操作
  • proc完成其迭代
  • 进程块-队列中仍有未处理的消息
  • 我可以想出几种方法来修复它,但没有一种是有利的

    解决方案1 我可以调整sync以在处理过程中保持互斥锁:

    proc()
    {
        while(true)
        {
            block_until_notify();
            Queue to_process;
    
            mutex.lock();
            to_process.add( queue.take_all() );
    
            foreach(message in to_process)
            {
                process_message(message);
            }
            mutex.unlock(); 
        }
    }
    
    但这意味着线程以独占方式运行:recv或proc都处于活动状态,但不是两者都处于活动状态

    解决方案2 我可以移除该块并通知

    recv()
    {
        while(true)
        {
            messages = receive_messages();
    
            mutex.lock();
            queue.add(messages);
            mutex.unlock();
        }
    }
    
    proc()
    {
        while(true)
        {
            Queue to_process;
    
            mutex.lock();
            to_process.add( queue.take_all() );
            mutex.unlock();
    
            foreach(message in to_process)
            {
                process_message(message);
            }
    
        }
    }
    
    但这意味着proc将在一个繁忙的等待循环中运行,只有在recv向队列添加消息时才会阻塞

    问题 我想要一个解决方案,其中proc和recv不独家运行,没有繁忙的等待。
    有人知道我能做什么吗?

    我想如果消费者在排干队列后检查是否有空队列,你就可以通过了

    proc()
    {
        while(true)
        {
            Queue to_process;
    
            mutex.lock();
    
            if (queue.empty()) {
               mutex.unlock();
               block_until_notify();
               mutex.lock();
            }
    
            to_process.add( queue.take_all() );
    
            mutex.unlock();
    
            foreach(message in to_process)
            {
                process_message(message);
            }
    
        }
    }
    

    我相信这会修正你提到的比赛条件

    您的
    阻塞\u直到\u notify()
    函数可能是一个条件变量。方法是更改该函数,以便锁定互斥锁,检查队列是否为空,然后等待通知。如果队列不是空的,则继续处理它。处理完队列后,返回block_notify函数并重复该过程,在阻塞之前再次检查队列是否为空


    如果您没有使用某种条件变量,那么我建议使用信号量。在Windows系统上,每次消息添加到队列中时,您都会调用
    releasesmaphore
    。接收器将调用信号量句柄上的
    WaitForSingleObject
    。这将在循环中完成,循环将继续重复,即使队列为空,直到等待阻塞。

    谢谢您的回答。“我也相信这会解决比赛条件。”达马库斯塔斯:这实际上是另一个答案第一段中建议的解决方案。谢谢你对信号灯的建议。