c++ winapi threads

c++ winapi threads

本文关键字:threads winapi c++      更新时间:2023-10-16

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

假设按下"开始"按钮时启动了几个线程。假设这些线程是密集型的(它们继续运行/总是有一些东西要处理)。

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

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

语言: C++

操作系统:视窗

问题:

WrapperFunc(function, param)    
{
     // what to write here ?
     // if i write this:
     function(param);
     // i cannot stop the function from executing
}
  • 我应该如何构造包装器函数才能正确停止线程?(不使用 TerminateThread 或其他一些函数)

  • 如果程序员动态分配一些内存怎么办?如何在关闭前释放它线程?(请注意,当我按下"停止按钮"时,线程仍在处理数据)我虽然关于重载新运算符或只是强加预定义的使用动态分配内存时使用的函数。然而,这意味着使用此 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,...);

一种解决方案是使用某种信号告诉线程停止工作。通常,这可以是通常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的函数来执行实际处理。但是,如果它包含可能需要时间的操作,则最终会再次遇到第一个问题。

请参阅我对这个类似问题的回答:

如何保证我的 win32 应用快速关机?

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

只要您使用的任何库都具有合理的异常感知能力并使用 RAII,这就可以很好地工作。但是,我还没有成功地使用 boost::threads 来解决这个问题,因为它不会将挂起的线程置于可警报的等待状态,因此 QueueUserAPC 无法唤醒它们。

如果你不希望线程将执行的函数的"程序员"处理"stop"事件,让线程执行一个处理"stop"事件的"you"函数,当该事件没有信号时执行"程序员"函数......

换句话说,"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);
    }
}