在函数调用中定义函数

时间:2012-01-28 02:18:29

标签: c++ winapi function

我有一个想法,可以节省时间,包括创建一个临时函数,用作需要它的函数的参数。我之后的行为是在新线程中以简单的方式(使用Win32 API)执行操作,而不必定义我将使用的所有类型的函数。

以下是一个例子:

void msg (const string & message) {
    MessageBox (0, message.c_str(), "Message", 0);
}

这将生成一个消息框,但您的程序将暂停,直到它关闭。解决方案是为与主线程同时运行的消息框创建一个线程。

void msg (const string & message) {
    CreateThread (0, 0, 
    (LPTHREAD_START_ROUTINE)({MessageBox (0, message.c_str(), "Message", 0);}), 
    0, 0, 0);
}

在这种情况下,LPTHREAD_START_ROUTINE被定义为
typedef DWORD (*LPTHREAD_START_ROUTINE)(LPVOID param);

由于我有多个函数需要另一个线程来实现这样的目的,所以将函数放在CreateThread的调用中似乎运行良好。

但是说我想使用LPVOID param。我想知道这种方法的标准是什么,以及我在哪里可以找到如何将它用于更高级的技术。此外,我知道在一个函数中使用它将存储它供以后使用(例如,一个消息循环函数,你可以添加消息来处理和相应的函数调用)是一个坏主意,因为该函数是临时的,不会是能够在需要时被调用。除了线程这样的东西之外还有什么用处吗?为了使用它而在其他地方生成一行函数会很烦人吗?

2 个答案:

答案 0 :(得分:2)

它被称为“lambda”。它们对于除此之外的许多目的非常有用,并且在C ++ 11标准中。您可以在最新的GCC和MSVC中找到它们。但是,MSVC的当前实现不允许转换为函数指针,因为标准当时没有指定这样的转换。 VC11将实现此转换。此代码符合标准C ++ 11:

void msg (const string & message) {
    CreateThread (0, 0, 
    [](LPVOID* param) { MessageBox (0, message.c_str(), "Message", 0); }, 
    0, 0, 0);
}

答案 1 :(得分:0)

有时候lambdas不是标准的另一种方式 - 你可以定义函数本地类并定义该类中的内部函数。类似的东西:

void msg(const string &message)
{
    struct message_box
    {
        static DWORD WINAPI display(LPVOID param)
        {
            /// do the action
            return 0;
        }
    };

    ::CreateThread(0, 0, 
        &message_box::display, 
        0, 0, 0);
}

现在让我们考虑你的问题。您想在STL的std :: string中传递消息文本。由于它占用了可以被初始线程释放的动态内存,因此并行运行的新线程必须保证消息文本仍然可用。这可以通过复制(可以使用lambda的按值捕获 - [=]介绍人)或共享引用(通过引用计数,让我们说)来完成。让我们考虑复制:

void msg(const string &message)
{
    struct message_box
    {
        static DWORD WINAPI display(void *param)
        {
            MessageBox(0, ((string *)param)->c_str(), "Message", 0);
            delete (string *)param;
            return 0;
        }
    };

    string *clone = new string(message);

    ::CreateThread(0, 0, 
        &message_box::display, 
        clone, 0, 0);
}

请注意,副本在初始线程中分配并在新线程中销毁。这需要您的CRT提供多线程支持。

如果新线程无法启动,最终会导致内存被孤立。让我们解决这个问题:

void msg(const string &message)
{
    struct message_box
    {
        static DWORD WINAPI display(void *param)
        {
            auto_ptr<string> message((string *)param);
            MessageBox(0, message->c_str(), "Message", 0);
            return 0;
        }
    };

    auto_ptr<string> clone(new string(message));

    if (::CreateThread(0, 0, &message_box::display, clone.get(), 0, 0))
        clone.release(); // release only if the new thread starts successfully.
}

由于内存由CRT管理,因此必须在新线程中初始化CRT,这不是由CreateThread API完成的。您必须改为使用CRT beginthread / beginthreadex:

void msg(const string &message)
{
    struct message_box
    {
        static unsigned int WINAPI display(void *param)
        {
            auto_ptr<string> message((string *)param);
            MessageBox(0, message->c_str(), "Message", 0);
            return 0;
        }
    };

    auto_ptr<string> clone(new string(message));

    if (_beginthreadex(0, 0, &message_box::display, clone.get(), 0, 0))
        clone.release(); // release only if the new thread starts successfully.
}

此解决方案不考虑线程本身作为资源泄露的问题。但是,我相信您可能会在stackoverflow.com上找到另一个帖子:)

谢谢)