⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 active.html

📁 Windows API Tutorials, Windows API编程最好的手册.文档格式专门制作成为各个章节相互关联的html格式,大家可以像查阅msdn一样方便使用.各个章节的内容如下: Wi
💻 HTML
字号:
<html>
<head>
<title>Active Objects</title>
<meta  name="description" content="Reliable software Win32 Tutorial: Threads">
<meta name="keywords" content="reliable, software, windows, cplusplus, source code, example, tutorial, thread, multitasking, synchronization, critical section, semaphore, event, threads, object oriented">
</head>

<body background="../images/grid.gif" bgcolor="white" text="black">


<table cellpadding=10 width="100%">
<tr>
   <td width=100 align=center valign=middle>
      <a href="../index.htm">
      <img src="../images/rsbullet.gif" alt="RS" border=0 width=39 height=39>
      <br>Home</a>
   <td><font face="arial" color="#009966">
       <h1 align=center>Using Threads</h1>
       </font>
</table>


<p>
<table width="100%">
<tr>
   <td width=80> <!-- Left margin -->
   <td> <!-- Middle column, there is also the right margin at the end -->

   <table cellpadding=10 cellspacing=0 width="100%">
   <tr>
   <td bgcolor="#ffffff">


<hr>
<font size="+1"><b>Multitasking is one of the most difficult</b></font> aspects of programming. It makes it even more important to provide a simple set of abstractions and to encapsulate it in a nice object-oriented shell. In the OO world, the natural counterpart of the thread (which is a strictly procedural abstraction) is the <b>Active Object</b>. An active object owns a captive thread that performs certain tasks asynchronously. This thread has access to all the internal (private) data and methods of the object. The public interface of the Active Object is available to external agents (e.g., to the main thread, or to the Windows thread carrying messages) so that they, too, can manipulate the state of the object and that of the captive thread, albeit in a very controlled and restricted manner.
<p>An Active Object is built upon a framework called <b>ActiveObject</b>. The implementor of the derived class is supposed to provide the implementation for the pure virtual methods <i>InitThread</i>, <i>Run</i> and <i>Flush</i> (as well as write the destructor).
<hr>

<pre><font face="courier">class <font color="#cc0066"><b>ActiveObject</b></font>
{
public:
    ActiveObject ();
    virtual ~ActiveObject () {}
    void Kill ();

protected:
    virtual void InitThread () = 0;
    virtual void Run () = 0;
    virtual void FlushThread () = 0;

    static DWORD WINAPI ThreadEntry (void *pArg);

    int             _isDying;
    Thread          _thread;
};


</font></pre>
<hr>
The constructor of the ActiveObject initializes the captive thread by passing it a pointer to a function to be executed and a pointer to "this." We have to disable the warning about using "this" before it is fully constructed. We know that it won't be used too early, because the thread is created in the inactive state. The constructor of the derived class is supposed to call <i>_thread.Resume ()</i> in order to activate it.
<hr>
<pre><font face="courier"><font color="#cc0066">// The constructor of the derived class
// should call
//    _thread.Resume ();
// at the end of construction</font>

<font color="#cc0066"><b>ActiveObject::ActiveObject</b></font> ()
: _isDying (0),
#pragma warning(disable: 4355) <font color="#cc0066">// 'this' used before initialized</font>
  _thread (ThreadEntry, this)
#pragma warning(default: 4355)
{
}

</font></pre>
<hr>
The method <i>Kill</i> calls the virtual method <i>FlushThread</i> -- it is supposed to release the thread from any wait state and let it run ahead to check the <i>_isDying</i> flag.
<hr>
<pre><font face="courier">void <font color="#cc0066"><b>ActiveObject::Kill</b></font> ()
{
    _isDying++;
    FlushThread ();
    <font color="#cc0066">// Let's make sure it's gone</font>
    _thread.WaitForDeath ();
}

</font></pre>
<hr>
We also have a framework for the <i>ThreadEntry</i> function (it's a static method of ActiveObject, so we can specify the calling convention required by the API). This function is executed by the captive thread. The argument it gets from the system is the one we passed to the constructor of the thread object-- the "this" pointer of the Active Object. The API expects a void pointer, so we have to do an explicit cast to the ActiveObject pointer. Once we get hold of the Active Object, we call its pure virtual method InitThread, to make all the implementation specific preparations, and then call the main worker method, <i>Run</i>. The implementation of <i>Run</i> is left to the client of the framework.
<hr>
<pre><font face="courier">DWORD WINAPI <font color="#cc0066"><b>ActiveObject::ThreadEntry</b></font> (void* pArg)
{
    ActiveObject * pActive = (ActiveObject *) pArg;
    pActive-&gt;InitThread ();
    pActive-&gt;Run ();
    return 0;
}

</font></pre>
<hr>
The Thread object is a thin encapsulation of the API. Notice the flag <b>CREATE_SUSPENDED</b> which assures that the thread doesn't start executing before we are done with the construction of the <i>ActiveObject</i>.
<hr>

<pre><font face="courier">class <font color="#cc0066"><b>Thread</b></font>
{
public:
    Thread ( DWORD (WINAPI * pFun) (void* arg), void* pArg)
    {
        _handle = <font color="#000099"><b>CreateThread</b></font> (
            0, <font color="#cc0066">// Security attributes</font>
            0, <font color="#cc0066">// Stack size</font>
            pFun,
            pArg,
            CREATE_SUSPENDED,
            &amp;_tid);
    }
    ~Thread () { <font color="#000099"><b>CloseHandle</b></font> (_handle); }
    void Resume () { <font color="#000099"><b>ResumeThread</b></font> (_handle); }
    void WaitForDeath ()
    {
        <font color="#000099"><b>WaitForSingleObject</b></font> (_handle, 2000);
    }
private:
    HANDLE _handle;
    DWORD  _tid;     <font color="#cc0066">// thread id</font>
};

</font></pre>
<hr>
<font size="+1"><b>Synchronization is what really makes</b></font> multitasking so hard. Let's start with mutual exclusion. Class <i>Mutex</i> is a thin encapsulation of the API. You embed Mutexes in your Active Object and then use them through Locks. A <i>Lock</i> is a clever object that you construct on the stack and for the duration of its lifetime your object is protected from any other threads. Class Lock is one of the applications of the <a href="../resource/index.htm">Resource Management</a> methodology. You have to put <i>Locks</i> inside all the methods of your Active Object that access data shared with the captive thread.
<hr>
<pre><font face="courier">class <font color="#cc0066"><b>Mutex</b></font>
{
    friend class <font color="#cc0066"><b>Lock</b></font>;
public:
    Mutex () { InitializeCriticalSection (&amp; _critSection); }
    ~Mutex () { DeleteCriticalSection (&amp; _critSection); }
private:
    void Acquire ()
    {
        <font color="#000099"><b>EnterCriticalSection</b></font> (&amp; _critSection);
    }
    void Release ()
    {
        <font color="#000099"><b>LeaveCriticalSection</b></font> (&amp; _critSection);
    }

    CRITICAL_SECTION _critSection;
};

class <font color="#cc0066"><b>Lock</b></font>
{
public:
    <font color="#cc0066">// Acquire the state of the semaphore</font>
    Lock ( Mutex &amp; mutex )
        : _mutex(mutex)
    {
        _mutex.Acquire();
    }
    <font color="#cc0066">// Release the state of the semaphore</font>
    ~Lock ()
    {
        _mutex.Release();
    }
private:
    Mutex &amp; _mutex;
};
</font></pre>

<hr>
An <i>Event</i> is a signalling device that threads use to communicate with each other. You embed an <i>Event</i> in your active object. Then you make the captive thread wait on it until some other thread releases it. Remember however that if your captive thread waits on a event it can't be terminated. That's why you should call <i>Release</i> from the <i>Flush</i> method.
<hr>

<pre><font face="courier">class <font color="#cc0066"><b>Event</b></font>
{
public:
    Event ()
    {
        // start in non-signaled state (red light)
        // auto reset after every Wait
        _handle = <font color="#000099"><b>CreateEvent</b></font> (0, FALSE, FALSE, 0);
    }

    ~Event ()
    {
        <font color="#000099"><b>CloseHandle</b></font> (_handle);
    }

    // put into signaled state
    void Release () { <font color="#000099"><b>SetEvent</b></font> (_handle); }
    void Wait ()
    {
        // Wait until event is in signaled (green) state
        <font color="#000099"><b>WaitForSingleObject</b></font> (_handle, INFINITE);
    }
    operator HANDLE () { return _handle; }
private:
    HANDLE _handle;
};
</font></pre>
<hr>
To see how these classes can be put to use, I suggest a little side trip. You can jump to the page that explains how the  <a href="../recorder.html">Frequency Analyzer</a> uses the ActiveObject class to update the display asynchronously. Or, you can study a somehow simpler example of a <a href="watcher.html">Folder Watcher</a> that waits quietly watching a folder and wakes up only when a change happens.
<p>I wish I could say programming with threads was simple. It is, however, simpler if you use the right kind of primitives. The primitives I advertised here are <i>ActiveObject, Thread, Mutex, Lock</i> and <i>Event</i>. Some of them are actually available in MFC. For instance, they have a Lock object (or is it CLock?) whose destructor releases the critical section (theirs is slightly less convenient because of the "two-step" construction-- you have to create it and then take it in two separate steps-- as if you'd want to create it and then <i>not</i> take it). Other than that, MFC only offers some thin veneer over the API, nothing exciting.
<p>You might also recognize some of the mechanisms I presented here in the <b>Java</b> programming language. Of course, when you have the liberty of designing multitasking into the language, you can afford to be elegant. Their version of <i>ActiveObject</i> is called <i>Runnable</i> and it has the <i>run</i> method. Every Java object potentially has a built-in mutex and all you have to do to take a lock is to declare a method (or a scope) <i>synchronized</i>. Similarly, the events are implemented with the <i>wait</i> and <i>notify</i> calls inside any <i>synchronized</i> method. So, if you know how to program in Java, you know how to program in C++ (as if there were people fluent in Java, but ignorant of C++).
<hr>
   </table>
   <td width=60>
</table>


</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -