[win] ActiveObject на QueueUserAPC
От: Abyx Россия  
Дата: 27.04.11 18:00
Оценка:
Насколько жизнеспособна идея сделать active object используя очередь QueueUserAPC?

#include <cassert>
#include <functional>
#include <utility>
#include <boost/noncopyable.hpp>
#include <Windows.h>

class ActiveObject
{
public:
    ActiveObject() : terminating(new bool(false))
    {
        hThread = ::CreateThread(nullptr, 0, &threadFn, this, 0, nullptr);
        assert(hThread != NULL);
    }
    ~ActiveObject()
    {
        invoke([this]{ *terminating = true; }); // "terminating" flag will set only when queue is empty

        auto waitResult = WaitForSingleObject(hThread, 42000 /* 42 sec */);
        assert(waitResult == WAIT_OBJECT_0); // you can use ProcessExplorer to kill the thread, but memory shall leak.
        // with some luck, thread can awake and terminate itself

        CloseHandle(hThread);
    }

    template<typename Callable>
    void invoke(Callable&& message) // replace Callable with std::function if executable will be too big
    {
        class Message : boost::noncopyable
        {
        public:
            Message(HANDLE hThread, Callable&& message) : fn(message)
            {
                auto ok = QueueUserAPC(&apcFunc, hThread, (ULONG_PTR)this);
                assert(ok != 0); ok;
            }

        private:
            static void __stdcall apcFunc(ULONG_PTR param)
            {
                auto that = (Message*)param;
                try
                {
                    that->fn();
                }
                catch(...) // if thread will die - all messages will be lost
                {
                    assert(!"something wrong happen");
                }
                delete that;
            }

            Callable fn;
        };

        new Message(hThread, std::forward<Callable>(message));
    }
private:

    static DWORD __stdcall threadFn(LPVOID param)
    {
        auto that = (ActiveObject*)param;
        auto terminating = that->terminating; // we create a copy, valid even when ActiveObject will be destroyed

        while(!terminating)
            ::SleepEx(INFINITE, TRUE);

        delete terminating;
        return 0;
    }

    HANDLE hThread;
    volatile bool* terminating;
};

// ======== test code ========

#include <iostream>

int main()
{
    { // just a scope for ActiveObject
        ActiveObject a;
        a.invoke([]{ std::cout << "I'm working o_O" << std::endl; });
        a.invoke([]{
            std::cout << "Now, I'm gonna sleep for a while" << std::endl;
            Sleep(2000);
        });

        Sleep(500);
        std::cout << "Main thread works too" << std::endl;
    }
    std::cout << "ActiveObject died" << std::endl;
}
In Zen We Trust
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.