2012-06-14 65 views
1

这些天,我想了解更多有关线程在Windows中的东西。我想到了这个实际应用:C++ winapi线程

假设按下按钮“开始”时有多个线程启动。假设这些线程是密集的(他们继续运行/总是有一些工作)。

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

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

语言:C++

操作系统:Windows

问题:

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,...); 

回答

0

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

I.e.是这样的:

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的函数来处理实际的处理。但是,如果它包含可能需要时间的操作,则会再次遇到第一个问题。

+2

考虑使用'volatile'关键字来防止编译器导致布尔值被缓存并保存在一个寄存器中,从而防止线程中的值发生变化。 – 2012-06-14 10:26:50

+0

问题是我想让用户不关心在线程函数中停止,只需编写功能。 –

+0

@infact好主意,完成。 –

0

见我回答这个类似的问题:

How do I guarantee fast shutdown of my win32 app?

基本上,你可以使用函数QueueUserAPC排队会抛出异常的PROC。这个异常应该在你的线程过程中一直冒泡到'catch'。

只要您使用的任何库都具有相当的异常感知能力并使用RAII,就可以非常好地工作。但是,我并没有成功地使用boost :: threads,因为它不会将挂起的线程置于可警告的等待状态,所以QueueUserAPC无法唤醒它们。

0

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

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

现在您正在进入整个工作/作业池系统。另外,这并不能解决繁忙循环中取消作业的问题。 – 2012-06-14 11:00:20

+0

如果我使用while(!event),用户函数(job)将会运行并且永远不会退出(注意thread_function中的while(1)循环)=>包装函数是无用的 –

+0

@infact - 取消不是问题:) –