参考:
意图:可控制的线程池
贴一段chrome的封装代码
// Copyright (c) 2012 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.#include "base/win/object_watcher.h"#include "base/bind.h"#include "base/logging.h"namespace base {namespace win {//-----------------------------------------------------------------------------ObjectWatcher::ObjectWatcher() : weak_factory_(this), object_(NULL), wait_object_(NULL), origin_loop_(NULL) {}ObjectWatcher::~ObjectWatcher() { StopWatching();}bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { CHECK(delegate); if (wait_object_) { NOTREACHED() << "Already watching an object"; return false; } // Since our job is to just notice when an object is signaled and report the // result back to this thread, we can just run on a Windows wait thread. DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE; // DoneWaiting can be synchronously called from RegisterWaitForSingleObject, // so set up all state now. callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(), delegate); object_ = object; origin_loop_ = MessageLoop::current(); if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, this, INFINITE, wait_flags)) { NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError(); object_ = NULL; wait_object_ = NULL; return false; } // We need to know if the current message loop is going away so we can // prevent the wait thread from trying to access a dead message loop. MessageLoop::current()->AddDestructionObserver(this); return true;}bool ObjectWatcher::StopWatching() { if (!wait_object_) return false; // Make sure ObjectWatcher is used in a single-threaded fashion. DCHECK(origin_loop_ == MessageLoop::current()); // Blocking call to cancel the wait. Any callbacks already in progress will // finish before we return from this call. if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) { NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError(); return false; } weak_factory_.InvalidateWeakPtrs(); object_ = NULL; wait_object_ = NULL; MessageLoop::current()->RemoveDestructionObserver(this); return true;}HANDLE ObjectWatcher::GetWatchedObject() { return object_;}// staticvoid CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { DCHECK(!timed_out); // The destructor blocks on any callbacks that are in flight, so we know that // that is always a pointer to a valid ObjectWater. ObjectWatcher* that = static_cast(param); that->origin_loop_->PostTask(FROM_HERE, that->callback_); that->callback_.Reset();}void ObjectWatcher::Signal(Delegate* delegate) { // Signaling the delegate may result in our destruction or a nested call to // StartWatching(). As a result, we save any state we need and clear previous // watcher state before signaling the delegate. HANDLE object = object_; StopWatching(); delegate->OnObjectSignaled(object);}void ObjectWatcher::WillDestroyCurrentMessageLoop() { // Need to shutdown the watch so that we don't try to access the MessageLoop // after this point. StopWatching();}} // namespace win} // namespace base
测试代码:
// Copyright (c) 2011 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.#include#include "base/message_loop.h"#include "base/win/object_watcher.h"#include "testing/gtest/include/gtest/gtest.h"namespace base {namespace win {namespace {class QuitDelegate : public ObjectWatcher::Delegate { public: virtual void OnObjectSignaled(HANDLE object) { MessageLoop::current()->Quit(); }};class DecrementCountDelegate : public ObjectWatcher::Delegate { public: explicit DecrementCountDelegate(int* counter) : counter_(counter) { } virtual void OnObjectSignaled(HANDLE object) { --(*counter_); } private: int* counter_;};void RunTest_BasicSignal(MessageLoop::Type message_loop_type) { MessageLoop message_loop(message_loop_type); ObjectWatcher watcher; EXPECT_EQ(NULL, watcher.GetWatchedObject()); // A manual-reset event that is not yet signaled. HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); QuitDelegate delegate; bool ok = watcher.StartWatching(event, &delegate); EXPECT_TRUE(ok); EXPECT_EQ(event, watcher.GetWatchedObject()); SetEvent(event); MessageLoop::current()->Run(); EXPECT_EQ(NULL, watcher.GetWatchedObject()); CloseHandle(event);}void RunTest_BasicCancel(MessageLoop::Type message_loop_type) { MessageLoop message_loop(message_loop_type); ObjectWatcher watcher; // A manual-reset event that is not yet signaled. HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); QuitDelegate delegate; bool ok = watcher.StartWatching(event, &delegate); EXPECT_TRUE(ok); watcher.StopWatching(); CloseHandle(event);}void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) { MessageLoop message_loop(message_loop_type); ObjectWatcher watcher; int counter = 1; DecrementCountDelegate delegate(&counter); // A manual-reset event that is not yet signaled. HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); bool ok = watcher.StartWatching(event, &delegate); EXPECT_TRUE(ok); SetEvent(event); // Let the background thread do its business Sleep(30); watcher.StopWatching(); MessageLoop::current()->RunAllPending(); // Our delegate should not have fired. EXPECT_EQ(1, counter); CloseHandle(event);}void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) { // Simulate a MessageLoop that dies before an ObjectWatcher. This ordinarily // doesn't happen when people use the Thread class, but it can happen when // people use the Singleton pattern or atexit. HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); // not signaled { ObjectWatcher watcher; { MessageLoop message_loop(message_loop_type); QuitDelegate delegate; watcher.StartWatching(event, &delegate); } } CloseHandle(event);}} // namespace//-----------------------------------------------------------------------------TEST(ObjectWatcherTest, BasicSignal) { RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT); RunTest_BasicSignal(MessageLoop::TYPE_IO); RunTest_BasicSignal(MessageLoop::TYPE_UI);}TEST(ObjectWatcherTest, BasicCancel) { RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT); RunTest_BasicCancel(MessageLoop::TYPE_IO); RunTest_BasicCancel(MessageLoop::TYPE_UI);}TEST(ObjectWatcherTest, CancelAfterSet) { RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT); RunTest_CancelAfterSet(MessageLoop::TYPE_IO); RunTest_CancelAfterSet(MessageLoop::TYPE_UI);}TEST(ObjectWatcherTest, OutlivesMessageLoop) { RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT); RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO); RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);}} // namespace win} // namespace base