使用 CreateThreadpoolWork/SubmitThreadpoolWork 时将不同的值传递给回调函数

Posted

技术标签:

【中文标题】使用 CreateThreadpoolWork/SubmitThreadpoolWork 时将不同的值传递给回调函数【英文标题】:Pass different values to callback function when using CreateThreadpoolWork/ SubmitThreadpoolWork 【发布时间】:2021-10-04 13:39:42 【问题描述】:

我目前正在学习作为 WinAPI 一部分的线程池 API。我成功创建了一个线程池并使用SubmitThreadpoolWork 来执行工作线程。但是,到目前为止,我只能将一个静态值传递给所有工作线程(指定为 CreateThreadpoolWork 函数的 2. 参数)。如何将不同的值传递给每个工作线程?

我的回调函数:

void CALLBACK test(PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work) 

    Sleep(2000);
    int* val = (int*)Parameter;
    std::wcout << (*val) << std::endl;

我的主要功能:

int main() 

    TP_CALLBACK_ENVIRON callBackEnviron;
    PTP_POOL pool = NULL;
    PTP_CLEANUP_GROUP cleanupgroup = NULL;
    PTP_WORK_CALLBACK workcallback = test;
    PTP_TIMER timer = NULL;
    PTP_WORK work = NULL;

    InitializeThreadpoolEnvironment(&callBackEnviron);
    pool = CreateThreadpool(NULL);
    SetThreadpoolThreadMaximum(pool, 8);
    cleanupgroup = CreateThreadpoolCleanupGroup();
    SetThreadpoolCallbackPool(&callBackEnviron, pool);
    SetThreadpoolCallbackCleanupGroup(&callBackEnviron, cleanupgroup, NULL);

    for (int i = 0; i < 20; ++i)
    
        work = CreateThreadpoolWork(workcallback, &i, &callBackEnviron);
        SubmitThreadpoolWork(work);
    

    WaitForThreadpoolWorkCallbacks(work, FALSE);
    CloseThreadpoolWork(work);
    CloseThreadpoolCleanupGroupMembers(cleanupgroup, FALSE, NULL);
    CloseThreadpoolCleanupGroup(cleanupgroup);
    CloseThreadpool(pool);

请注意,每个工作线程都会在 for-loop 完成之前输出“20”,这是 i 的最终值。但是,我希望每个工作线程在执行相应的SubmitThreadpoolWork 调用时输出i 的值。我也相当确定 CreateThreadpoolWork 不应该在循环中被调用,但我不确定如何尝试它。

【问题讨论】:

【参考方案1】:

您正在向每个工作项传递一个指向循环计数器变量的指针。当循环结束时,该变量将超出范围并被销毁。因此,在该时间之前运行的任何工作人员都将作用于共享内存,而在该时间之后运行的任何工作人员都将作用于指向无效内存的悬空指针,这是未定义的行为

您需要:

为每个工作线程动态分配一个新变量,并在回调中释放该变量:
void CALLBACK test(PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work) 
    Sleep(2000);
    int* val = static_cast<int*>(Parameter);
    std::wcout << *val << std::endl;
    delete val;


for (int i = 0; i < 20; ++i)

    int *val = new int(i);
    work = CreateThreadpoolWork(workcallback, val, &CallBackEnviron);
    if (work)
        SubmitThreadpoolWork(work);
    else
        delete val;

将整数的类型转换为指针,然后在回调中将其类型转换回整数:
void CALLBACK test(PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work) 
    Sleep(2000);
    int val = reinterpret_cast<int>(Parameter);
    std::wcout << val << std::endl;


for (int i = 0; i < 20; ++i)

    work = CreateThreadpoolWork(workcallback, reinterpret_cast<void*>(i), &CallBackEnviron);
    if (work)
        SubmitThreadpoolWork(work);

【讨论】:

感谢您的解释,我能够修复我的代码。所以根据你的回答可以在for循环中调用CreateThreadpoolWork吗? 当然是。为什么你会认为不是?它只是一个函数调用,和其他任何函数一样。

以上是关于使用 CreateThreadpoolWork/SubmitThreadpoolWork 时将不同的值传递给回调函数的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)