代码之家  ›  专栏  ›  技术社区  ›  Idan

线程同步

  •  0
  • Idan  · 技术社区  · 15 年前

    假设我有一个阻塞方法,让我们调用block()。

    由于我不希望我的主线程被阻塞,我可能会创建一个工作线程,它将调用阻塞。

    但是,我有另一个条件。

    我希望在5秒内返回对block的调用top,否则,我希望让主线程知道对block的调用失败并退出工作线程。

    对于这种情况,最好的解决方案是什么?

    我想是这样的: 创建一个Worker线程,在Worker线程中创建一个计时器对象,时间为5秒, 另外在调用前后调用gettickCount来阻塞和计算delta。

    此外,我将定义一个布尔isreturned指示块函数是否已经返回。 在块调用后设置为真。

    根据计时器函数中的布尔值,我决定如何继续:

    1. 如果布尔值是真的,我什么也不做。

    2. 如果布尔值为false,我可以在主线程上对apc onfailure或信号success事件进行排队,然后完全退出工作线程(问题是我不确定是否可以这样做)

    此外,在块函数返回后,我检查delta是否为lett,然后5秒 排队等候APC。(问题是退出调用线程是否也会取消计时器?因为基本上在那之后计时器就没用了)

    如果我能确定我可以取消计时器函数中的工作线程,我想我甚至不需要gettickcount的东西。

    谢谢!

    3 回复  |  直到 15 年前
        1
  •  2
  •   Ephphatha    15 年前

    我建议为此使用boost::threads库。您可以定期检查阻塞线程是否可接合(即,仍在工作),然后在五秒钟后中断它。然后,您需要编写阻塞函数来处理该中断并干净地退出。

    #include <boost/thread/thread.hpp>
    
    void Block(void)
    {
        //Do work and periodically call boost::this_thread::sleep()
        try
        {
            boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        }
        catch(boost::thread_interrupted const&)
        {
            return;
        }
    }
    
    int main(int argc, char *argv[])
    {
        boost::thread blockThread(Block); //If Block takes arguments, just add them as arguments to the constructor.
        time_t startTime = time(NULL);
    
        while(true)
        {
            if(blockThread.joinable() && (time(NULL) - startTime) > 5)
            {
                blockThread.interrupt();
            }
            //Do whatever you want while waiting for the thread to finish.
        }
    }
    

    编辑:检查 Thread Management 更多中断点的文档和boost threads类的定义。

    edit2:如果在等待阻塞线程完成时不需要在主线程中做任何工作,并且没有方便的地方来处理中断 Block() 您可以通过如下方式显式地终止线程:

    void Block(void)
    {
        //Do work
    }
    
    int main(args)
    {
        boost::thread blockThread(Block);
    
        //timed_join() returns false if the thread is still running after the specified time.
        if(!blockThread.timed_join(boost::posix_time::milliseconds(5000)))
        {   //detach() will kill the thread, any memory initialised in Block() will not be freed, any locals may or may not be freed either.
            blockThread.detach();
        }
    }
    
        2
  •  2
  •   Ben Karel    15 年前

    我认为你大概有正确的想法,尽管你可能想要 WM_TIMER 传递到主线程的消息,而不是可能阻塞的线程。否则,如果线程在计时器触发前阻塞,则计时器消息可能会丢失!类似地,检查在主线程而不是工作线程中经过的时间,因为如果 Block() 阻止,它不会返回,并且呼叫 GetTickCount() 之后 块() 永远不会发生。

    要在线程之间进行通信,最简单的方法可能是使用原子变量。您还可以让工作线程在成功时将消息传回主线程,如果主线程在5秒计时器触发时看不到消息,则应假定工作线程被阻塞。

    一般来说,杀死阻塞的线程是危险的。Java文档强烈反对做这件事,如果有的话,问题更严重的是C++。考虑到自己被警告了!

        3
  •  0
  •   AndersK    15 年前

    首先创建线程是一件昂贵的事情,所以每次调用块都这样做可能不是一个好主意。

    第二,解决这个问题的方法有很多,这也很大程度上取决于您的环境。例如,在Windows中,实现这一点的一种可能方法是使用带有消息队列的工作线程。然后,您定义了一些在工作线程中处理的消息。一个可以是wm_CallBlock,另一个可以是wm_Areyouready和wm_Yesiam,当您想调用block()时,您可以将该消息发布到工作线程,它将调用函数。通过消息,还可以传递block()所需的任何参数。因为你的功能是阻塞的-如果你然后发布一条消息wm youready,你将不会直接得到wm yesiam的回复。所以您可以在此基础上构建超时。