2

我在 C++Builder 2009 中编写多线程套接字聊天。
按照我需要做的,它几乎完成了,但我有一个小问题。我需要将 TMemo* 指针传递给 CreateThread WinAPI 函数,该函数将其向上转换为 void*。

我试过这样:

HANDLE xxx = MemoChat->Handle;
hNetThread = CreateThread(NULL, 0, NetThread, xxx, 0, &dwNetThreadId);
//...

然后,在 NetThread 函数中,

TMemo* MyMemo((HANDLE)lpParam);
TMemo* MyMemo((TMemo*)lpParam);

但它没有工作:(

问题是我如何才能真正正确地向下转换它,以便我可以在这个新线程中使用我的备忘录组件?

4

3 回答 3

3

称呼:

TMemo*     MemoChat   = // You defined that somewhere I assume
HANDLE     hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);

这里发生的情况是,您作为第三个参数传递的任何指针都将自动转换为 void 指针(或在 WinTerms LPVOID 中)。没关系,它不会改变它,它只会丢失类型信息,因为系统对您的对象一无所知。

新的线程起点:

DWORD NetThread(LPVOID lpParameter)
{
    TMemo*   MemoChat   = reinterpret_cast<TMemo*>(lpParameter);
    // Do your thread stuff here.
}

一旦你的线程启动方法被调用。只需将 void 指针转换回正确的类型,您应该能够再次开始使用它。

只是为了澄清其他误解。

HANDLE 是一个指针。
您可以将它作为参数传递给 NetThread()。

HANDLE 是指向系统控制下的指针的指针,它指向您正在使用的对象。那么为什么要使用双重间接。它允许系统移动对象(并更新其指针)而无需找到对象的所有所有者。所有者都有指向刚刚更新的指针的句柄。

这是一个老式的计算机科学概念,由于操作系统/硬件能够将主存储器交换到辅助存储器,因此在现代计算机中很少使用。但对于某些资源,它们仍然有用。如今,当需要手柄时,它们隐藏在远离用户的物体内。

于 2008-11-08T18:50:09.053 回答
2

请理解 HANDLE不是指针,而是 Win32 API 的一个概念。所以第一行将 LPVOID 转换为 HANDLE - 这是正确的,因为线程例程的参数实际上是作为句柄 (xxx) 给出的。但是,它会继续将 HANDLE 转换为 MyMemo 对象;这会将句柄中的位视为它们将形成一个地址 - 它们不是。

第二行进行完全相同的转换——它将句柄视为直接指针。

我想知道你为什么不将 MemoChat 本身传递给线程:

hNetThread = CreateThread(NULL, 0, NetThread, MemoChat, 0, &dwNetThreadId);
于 2008-11-08T15:59:39.070 回答
0

这更多是为了尝试澄清句柄与指针的关系,因为我认为马丁并不完全正确。

“指向指针的指针”确实被称为 HANDLE,它是一种常见的 CS 方法,允许操作系统在不明确知道应用程序层的情况下物理移动堆分配的内存块,应用程序层总是通过句柄访问它们。Classic 68K Mac OS 以这种方式工作。以这种方式工作的操作系统通常允许用户代码通过句柄以及直接在堆外分配内存。这种方法用于没有适当内存管理硬件的机器上。

然而,HANDLE这个词还有其他的用法,它们借用了之前用法的一些抽象,但有不同的实现。不透明指针(指向用户不知道的数据结构的指针 - PIMPL 成语)通常也称为 HANDLES。

此外,术语 HANDLE 可以简单地用于表示对对象的“引用”——可能是数组的索引。Unix 文件句柄(= 文件描述符)就是一个很好的例子。标准输入=0,标准输出=1,...

那么,以上哪些是 Windows API HANDLES?我看到了相互矛盾的报道。这份文件说:

Win32 中的句柄是用于标识资源或窗口的数字。它们不是指针或指向指针的指针。将它们视为身份证号码。

于 2008-11-08T23:24:10.980 回答