简体   繁体   English

线程同步

[英]thread synchronization

let's say i have a blocking method , let's call in Block(). 假设我有一个阻塞方法,让我们在Block()中调用。

as i don't want my main thread to block i might create a worker thread, that instead will call Block. 因为我不希望我的主线程阻塞,所以我可能会创建一个工作线程,而是调用Block。

however, i have another condition. 但是,我还有另一个条件。

i want the call to block to return in 5 seconds top, otherwise, i want to let the main thread know the call to Block failed and to exit the worker thread. 我希望阻塞的调用在5秒内返回,否则,我想让主线程知道对Block的调用失败并退出工作线程。

what would be the best solution to that scenario? 那种情况下最好的解决方案是什么?

i thought something like that: create a workher thread, in the worker thread to create a timer object with 5 seconds, and in addition to call gettickcount before and after the call to Block and calculate the delta. 我想过这样的事情:创建一个工作线程,在工作线程中创建一个5秒的计时器对象,并在调用Block之前和之后调用gettickcount并计算增量。

in addition i will define a boolean IsReturned indication whether the Block function returned already. 另外,我将定义一个布尔值IsReturned,指示Block函数是否已经返回。 after the Block call to set it true. 在Block调用之后将其设置为true。

according to that boolean in the Timer Function i decide how to proceed : 根据计时器函数中的布尔值,我决定如何继续:

  1. if the boolean is true i do nothing. 如果布尔值是真的,我什么也不做。

  2. if the boolean is false i can queue an APC OnFailure or maybe signal Sucess event on the main thread, and exit the worker thread forcfully (the thing is i'm not sure if i can do that) 如果布尔值为假,我可以在主线程上排队APC OnFailure或发出信号Sucess事件,然后强制退出工作线程(问题是我不确定是否可以这样做)

in addition after the block function return i check whether the delta is lett then 5 sec and queue an APC OnSucess. 另外,在返回块函数之后,我将检查增量是否为5秒,然后将APC OnSucess排队。 (the question is does exiting the caller thread cancels the timer also ? cause basically after that the timer is useless ) (问题是退出调用者线程也取消了计时器吗?基本上是在计时器无用之后造成的)

ps - if i can know for sure that i can cancel the worker thread within the timer function i don't think i even need the gettickcount stuff. ps-如果我可以确定我可以取消计时器函数中的工作线程,我不认为我什至不需要gettickcount东西。

thanks! 谢谢!

I think you have roughly the right idea, though you probably want the WM_TIMER messages delivered to the main thread, not the potentially-blocking thread. 我认为您的想法大致正确,尽管您可能希望将WM_TIMER消息传递到主线程,而不是可能阻塞的线程。 Otherwise, the timer messages might get lost, if the thread blocks before the timer fires! 否则,如果线程在计时器触发之前阻塞,则计时器消息可能会丢失! Similarly, check the elapsed time in the main thread rather than the worker, since if Block() blocks, it won't return, and the call to GetTickCount() after Block() will never happen. 同样,检查主线程而不是工作线程中的经过时间,因为如果Block()阻塞,它将不会返回,并且Block()之后对GetTickCount()的调用将永远不会发生。

To communicate between threads, the simplest thing would probably be to use an atomic variable. 在线程之间进行通信,最简单的方法可能是使用原子变量。 You could also have the worker pass a message back to the main thread on success, and if the main thread doesn't see the message when the 5-second timer fires, it should assume the worker thread blocked. 您还可以让工作线程在成功时将消息传递回主线程,并且如果在5秒计时器触发时主线程没有看到消息,则应假定工作线程被阻塞。

In general, killing a blocked thread can be dangerous. 通常,杀死被阻塞的线程可能很危险。 The Java documentation cautions strongly against doing it, and if anything, the problems are worse with C++. Java文档强烈警告不要这样做,如果有的话,C ++的问题会更严重。 Consider yourself warned! 考虑一下自己被警告!

I would suggest using the boost::threads library for this. 我建议为此使用boost :: threads库。 You can periodically check if the blocking thread is joinable (ie, still working) and then interrupt it after five seconds. 您可以定期检查阻塞线程是否可连接(即仍在工作),然后在五秒钟后将其中断。 You will then need to write the blocking function to handle that interruption and cleanly exit. 然后,您需要编写阻止功能来处理该中断并干净地退出。

#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.
    }
}

Edit: Check the Thread Management documentation for more interruption points and the definition for the boost threads class. 编辑:检查线程管理文档以获取更多中断点和boost线程类的定义。

Edit2: If you don't need to do any work in the main thread while waiting for the blocking thread to complete, and there is no convenient place to handle interrupts in Block() you can explicitly kill the thread with something like this: 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();
    }
}

First creating threads is an expensive thing so doing for each call to Block may not be a good idea. 首先创建线程是一件昂贵的事情,因此对每个Block的调用可能不是一个好主意。

Second there are numerous ways to solve this, it also depends heavily on your environment. 其次,有很多方法可以解决此问题,这也很大程度上取决于您的环境。 For instance in Windows a possible way of doing this would be to have a worker thread with a message queue. 例如,在Windows中,执行此操作的一种可能方法是使工作线程具有消息队列。 You then define a couple of messages which you handle in your worker thread. 然后,您定义一些在工作线程中处理的消息。 One could be WM_CALLBLOCK another could be WM_AREYOUREADY and WM_YESIAM, when you want to call Block() you could then just post that message to the worker thread and it would call the function. 一个可能是WM_CALLBLOCK,另一个可能是WM_AREYOUREADY和WM_YESIAM,当您要调用Block()时,您可以将该消息发布到工作线程中,然后它将调用该函数。 With the message you could also pass whatever parameters you need for Block(). 通过该消息,您还可以传递Block()所需的任何参数。 Since your function is blocking - if you then post a message WM_AREYOUREADY you will not get a WM_YESIAM reply directly. 由于您的功能正在阻止-如果您随后发布消息WM_AREYOUREADY,则不会直接收到WM_YESIAM答复。 So you could build your timeout on that. 因此,您可以在此基础上建立超时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM