c++ winapi线程

Posted

技术标签:

【中文标题】c++ winapi线程【英文标题】:c++ winapi threads 【发布时间】:2012-06-14 10:19:46 【问题描述】:

这些天来,我正在尝试了解有关 Windows 中线程的更多信息。我想过做这个实际应用:

假设按下“开始”按钮时启动了多个线程。假设这些线程是密集的(它们一直在运行/总是有一些工作要做)。

这个应用程序还有一个“停止”按钮。当按下此按钮时,所有线程都应该以一种很好的方式关闭:释放资源并放弃工作并返回它们在按下“开始”按钮之前的状态。

应用程序的另一个要求是线程运行的函数不应包含任何检查“停止”按钮是否被按下的指令。线程中运行的函数不应该关心停止按钮。

语言:C++

操作系统:Windows

问题:

WrapperFunc(function, param)    

     // what to write here ?
     // if i write this:
     function(param);
     // i cannot stop the function from executing

我应该如何构造包装函数,以便可以正确停止线程? (不使用 TerminateThread 或其他一些功能)

如果程序员动态分配一些内存怎么办?如何在关闭前释放它 线程?(请注意,当我按下“停止按钮”时,线程仍在处理数据) 我虽然关于重载 new 运算符或只是强加使用预定义的 动态分配内存时使用的函数。然而,这意味着 使用这个api的程序员受到了限制,这不是我想要的。

谢谢

编辑:描述我想要实现的功能的骨架。

struct wrapper_data

      void* (*function)(LPVOID);
      LPVOID *params;
;

/* 
this function should make sure that the threads stop properly
( free memory allocated dynamically etc )
*/
void* WrapperFunc(LPVOID *arg)    

     wrapper_data *data = (wrapper_data*) arg;
     // what to write here ?
     // if i write this:
     data->function(data->params);
     // i cannot stop the function from executing
     delete data;


// will have exactly the same arguments as CreateThread
MyCreateThread(..., function, params, ...)

    // this should create a thread that runs the wrapper function
    wrapper_data *data = new wrapper_data;
    data->function = function;
    data->params = params;

    CreateThread(..., WrapperFunc, (LPVOID) wrapper_data, ...);


thread_function(LPVOID *data)

   while(1)
   
        //do stuff
   


// as you can see I want it to be completely invisible 
// to the programmer who uses this
MyCreateThread(..., thread_function, (LPVOID) params,...);

【问题讨论】:

【参考方案1】:

一种解决方案是使用某种信号告诉线程停止工作。通常这可以是一个全局布尔变量,通常为false,但当设置为true 时,它会告诉线程停止。至于清理,在线程主循环完成后再从线程返回时进行。

即像这样:

volatile bool gStopThreads = false;  // Defaults to false, threads should not stop

void thread_function()

    while (!gStopThreads)
    
        // Do some stuff
    

    // All processing done, clean up after my self here


至于清理位,如果您将数据保存在结构或类中,您可以从线程外部强行杀死它们,如果您动态分配实例或让系统处理它,则只需 delete 实例如果创建例如在堆栈上或作为全局对象。当然,你的线程分配的所有数据(包括文件、套接字等)都必须放在这个结构或类中。


在包装器中保留停止功能的一种方法是在包装器中包含实际的主循环,以及对停止信号的检查。然后在主循环中调用一个类似doStuff 的函数来进行实际处理。但是,如果它包含可能需要时间的操作,您最终会再次遇到第一个问题。

【讨论】:

考虑使用 'volatile' 关键字来防止编译器导致布尔值被缓存并保存在寄存器中,从而防止值更改对线程可见。 问题是我希望用户不要关心在线程函数中停止,只需编写功能即可。 @QtLearner 添加了一段关于线程后清理的另一种方法。 @QtLearner 你不能让它对你的系统用户完全“不可见”,你不能从外部很好地杀死一个线程,并让它自动清理。线程必须寻找某种信号。如果它是一个全局变量,一个类中的成员变量或其他东西完全无关紧要。 同意。请评论我的回答。【参考方案2】:

查看我对这个类似问题的回答:

How do I guarantee fast shutdown of my win32 app?

基本上,您可以使用 QueueUserAPC 对引发异常的 proc 进行排队。异常应该一直冒泡到您的线程过程中的“捕获”。

只要您使用的任何库都具有合理的异常感知能力并使用 RAII,它就非常有效。但是,我还没有成功地使用 boost::threads 进行此操作,因为它不会将挂起的线程置于警报等待状态,因此 QueueUserAPC 无法唤醒它们。

【讨论】:

【参考方案3】:

如果您不希望线程将执行的函数的“程序员”处理“停止”事件,请让线程执行处理“停止”事件的“你”函数以及何时执行事件未发出信号执行“程序员”功能...

换句话说,“while(!event)”将在一个调用“job”函数的函数中。

代码示例。

typedef void (*JobFunction)(LPVOID params); // The prototype of the function to execute inside the thread

struct structFunctionParams

    int iCounter;
    structFunctionParams()
    
        iCounter = 0;
    
;

struct structJobParams

    bool bStop;
    JobFunction pFunction;
    LPVOID pFunctionParams;
    structJobParams()
    
        bStop = false;
        pFunction = NULL;
        pFunctionParams = NULL;
    
;

DWORD WINAPI ThreadProcessJob(IN LPVOID pParams)

    structJobParams* pJobParams = (structJobParams*)pParams;
    while(!pJobParams->bStop)   
    
        // Execute the "programmer" function
        pJobParams->pFunction(pJobParams->pFunctionParams);
       

    return 0;



void ThreadFunction(LPVOID pParams)

    // Do Something....
    ((structFunctionParams*)pParams)->iCounter ++;



int _tmain(int argc, _TCHAR* argv[])
   
    structFunctionParams stFunctionParams;

    structJobParams stJobParams;
    stJobParams.pFunction = &ThreadFunction;
    stJobParams.pFunctionParams = &stFunctionParams;




    DWORD dwIdThread = 0;
    HANDLE hThread = CreateThread( 
        NULL,
        0, 
        ThreadProcessJob,
        (LPVOID) &stJobParams, 0, &dwIdThread);
    if(hThread) 
       
            // Give it 5 seconds to work
        Sleep(5000);
        stJobParams.bStop = true; // Signal to Stop
        WaitForSingleObject(hThread, INFINITE); // Wait to finish
        CloseHandle(hThread);
    

【讨论】:

现在您正在进入一个完整的工作/工作池系统​​。此外,这并不能解决在繁忙循环期间取消作业的问题。 如果我使用 while(!event) 用户函数(作业)将运行并且永远不会退出(注意 thread_function 中的 while(1) 循环)=> 包装函数没用 @infact - 取消不是问题的一部分 :) @QtLearner - 这就是为什么我说 while 条件不在工作职能中 请提供一些代码,我不明白。问题是当我运行 thread_function (data->function(data->params); line ) 时,我失去了对执行的控制。

以上是关于c++ winapi线程的主要内容,如果未能解决你的问题,请参考以下文章

如何安全地调用 TerminateThread 和 FreeLibrary (WinAPI, C++)

C++ Winapi Owner 绘制的列表框动画

winApi使用c++创建进程

WINAPI--多线程与互斥锁(销票系统)

C#、C++、WinAPI - 从另一个进程获取窗口数

如何使用 C++ 和 winAPI 检查目录是不是存在 [重复]