分类
未分类

线程通讯

线程通讯

线程与线程之间通信,除了直接访问共享变量之外,还有一种更安全的方式,那就是消息循环。

建立线程消息循环

除了每个窗口都有一个消息循环以外,每个线程也都可以有一个消息循环。但是需要注意的是,为了节约资源,线程默认情况下不会建立消息循环,因为不是所有线程都会去接收消息。但是,如果你在线程函数中调用获取消息的函数的话,系统就会自动为线程创建消息循环。

总的来说,创建一个线程的消息循环,格式大致如下:

“`C++
DWORD WINAPI 线程函数(LPVOID lpParam)
{
// 一些初始化操作

<pre><code>// 调用 PeekMessage 去让系统建立消息循环
// 因为参数的最后一个传入的是 PM_NOREMOVE,所以原来的消息依然存在消息循环中
// 这里并不去判断消息,只是为了建立消息循环
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// 下面是消息循环主体
while (GetMessage(&msg, NULL, NULL, NULL))
{
switch (msg.message)
{
case 消息1:
消息1的处理;
break;
case 消息2:
消息2的处理;
break;
// 更多的消息处理
default:
// 和窗口消息循环不一样,线程消息循环可以没有默认消息处理
}
}
// 清理操作
return 0;
</code></pre>

}

<pre class="line-numbers prism-highlight" data-start="1"><code class="language-null"><br />&lt;p&gt;一旦你的线程函数执行在消息循环中,就会一直等待有人给这个线程发消息,直到线程收到了 &lt;code&gt;WM_QUIT&lt;/code&gt; 消息之后,线程才会退出。&lt;/p&gt;

&lt;p&gt;注意,当 &lt;code&gt;GetMessage()&lt;/code&gt; 获取到了 &lt;code&gt;WM_QUIT&lt;/code&gt; 消息的时候,就会返回 &lt;code&gt;FALSE&lt;/code&gt;。&lt;/p&gt;

&lt;h2&gt;向线程发消息&lt;/h2&gt;

&lt;p&gt;那么,怎样从另一个线程给某个指定的线程发消息呢?发送消息需要用到 &lt;code&gt;PostThreadMessage()&lt;/code&gt; 函数,这个函数的用法如下:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C++
BOOL PostThreadMessage(
DWORD idThread, // 目标线程的 ID
UINT Msg, // 要发送的消息
WPARAM wParam, // 消息的附加参数1
LPARAM IParam // 消息的附加参数2
);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这个函数的第一个参数,目标线程的ID 怎么获取呢?当我们在创建线程的时候,&lt;code&gt;CreateThread()&lt;/code&gt; 这个函数的最后一个参数返回的就是线程的ID,所以,传入这个ID就可以了。例如:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C++
DWORD id;
CreateThread(NULL, 0, fun, NULL, NULL, &amp;id);
PostThreadMessage(id, 消息, 0, 0);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;另外需要注意的一点是,因为线程执行时机的不确定性,当你调用 &lt;code&gt;PostThreadMessage()&lt;/code&gt; 的时候目标线程的消息循环可能还没建立,这个时候这个函数就会返回 FALSE。所以,你在发送线程消息的时候,需要检查一下这个函数的返回值,如果发送失败了,就需要重新发送这个消息。例如,当你确认目标线程消息循环是可用的时候,可以这样发送消息:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C++
while (!PostThreadMessage(id, 消息, 0, 0));&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;定义消息&lt;/h2&gt;

&lt;p&gt;如果你希望让你的线程退出,只需要发送一个 &lt;code&gt;WM_QUIT&lt;/code&gt; 消息就可以了。例如:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C++
PostThreadMessage(id, WM_QUIT, 0, 0);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;你可以向线程发送Windows定义的消息,也可以发送自定义的消息。可以看到,消息的变量类型是 &lt;code&gt;UINT&lt;/code&gt;,也就是说,任何正整数都可以当成消息发送。&lt;/p&gt;

&lt;p&gt;Windows 预定义了很多消息(1024条消息以内),如果你希望向线程发消息的话,使用的数字要大于 1024。微软将 &lt;code&gt;WM_USER&lt;/code&gt; 定义成了 1024,所以,你要定义自己的消息的话,可以这么定义:&lt;/p&gt;

&lt;p&gt;“`C++

<h1>define WM_MY_MESSAGE1 (WM_USER + 1)</h1>

<h1>define WM_MY_MESSAGE2 (WM_USER + 2)</h1>


下面给出一个例子,这个例子要实现:
1. 建议一个线程,线程建立一个消息循环;
2. 主线程给新建线程发送自定义的打印Hello world消息之后,新建线程输出Hello world

“`C++

define WM_HELLO_WORLD (WM_USER + 10086)

DWORD WINAPI fun(LPVOID lpParam)
{
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

while (GetMessage(&msg, NULL, NULL, NULL))
{
    switch (msg.message)
    {
    case WM_HELLO_WORLD:
        printf("Hello wolrd!");
        break;
    }
}

return 0;

}

int main()
{
DWORD idThread;
HANDLE hThread = CreateThread(NULL, 0, fun, NULL, NULL, &idThread);

while(!PostThreadMessage(idThread, WM_HELLO_WORLD, 0, 0))
{
    Sleep(100);
}

PostThreadMessage(idThread, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);

return 0;

}

“线程通讯”上的一条回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注