首先介绍下背景,我的线程是我自己创建的,里面需要用到复杂的算法,但完全不需要系统调用(当然也不需要分配内存)。你可以把他假想为一个对大量数据排序的算法。另外我的线程有一定的实时性要求,可以认为系统有一个电眼提供外部触发信号,在下一个触发信号到达前,必须处理完当前信号。目前考虑有3种办法:
1、在复杂算法内部经常性去判断下一个触发信号是否已到达,流程大致如下:
算法步骤1;
下一信号是否到达?到达则返回;
算法步骤2;
下一信号是否到达?到达则返回;
算法步骤3;
下一信号是否到达?到达则返回;
......
缺点:算法本身相当复杂,并不好简单的分为几个步骤,且相邻两次检查信号之间的步骤会运行多久,也很难估计(每次信号不同,使得算法每个步骤需要的时间也可能不同),这样就有可能下一信号已经到达一段时间后,才会停止处理当前信号。当前信号晚点处理完倒没什么关系,反正结果都没用了。但问题是可能造成下一种办法提到的连锁反应。
另外这种做法本身对算法程序的独立性/维护性都会造成影响。2、不终止当前信号的线程,让它自然结束。新建线程处理新的信号。
缺点:系统负荷不大时,这也是个办法。但系统负荷较大时,很可能当前信号的线程占用CPU,导致下一信号也不能被及时处理,从而造成连锁反应。甚至可能系统中线程越来越多,最终崩溃。3、在下一个触发信号到达时,如果当前信号未处理结束则使用TerminateThread强行终止。
这个方法应该能够克服上面的两个缺点,但查了好几天,都说TerminateThread会造成泄漏。《Windows 核心编程》提到,线程函数返回时能够确保:
1.在线程函数中创建的所有C + +对象均将通过它们的撤消函数正确地撤消。
2.操作系统将正确地释放线程堆栈使用的内存。
3.系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
4.系统将递减线程内核对象的使用计数。由于我的线程不会分配内存,所以主要问题应该在“释放线程堆栈”和“递减线程内核对象的使用计数”。我的问题是:
1.确实没有办法TerminateThread后释放线程堆栈吗?
2.TerminateThread后,通过CloseHandle是否可以达到“递减线程内核对象的使用计数”的效果?我觉得我的这个需求在一些需要实时进行产品检测的流水线上是很常见的,应该有比较好的解决办法才对。期望高手给予解答,非常感谢!分不够了,惭愧

解决方案 »

  1.   

    线程占的资源可能不仅是栈不需要合作而中断线程的方法是SetThreadContext,你可以用SetThreadContext使某个线程触发一个异常,那个线程的代码用try catch包着,这样就可以捕获异常,然后执行清理但合作总比不合作稳定
      

  2.   

    线程在上个信号没有处理完毕,就来了新的信号,这个现象在你的系统里应该属于发生概率比较小的事情吧?如果是大概率,那么感觉就要优化算法或者换更强劲的cpu了。如果是小概率,那么可以在接收到信号后,发送消息给线程,让线程自己处理,这样线程就不用提心吊胆地检测新信号有没有来,线程接收到消息后可以自己退出,让程序重新创建线程,也可以线程中断处理当前数据,重新初始化,处理新数据,我觉得这两种方式都可以。一己之见。
      

  3.   

    在该问题中有这样一个事实:
    假如当前正在处理信号A:
    突然很短时间内连续出现了信号B,C,D,E;
    当前时刻,只要停掉处理A,开始处理信号E,就可以了;而B,C,D信号没有必要处理的;
    另外,启动线程有一定开销的,所以能否只用一个线程来处理;在线程内部,利用几个类似状态的
    变量,如:
    CurrentState;//当前最后到达的信号状态
    ActiveState ; //正在进行计算的信号状态;
    UINT ThreadFunc(LPVOID pParam)
    {
       ...
       while(TRUE)
       {
           //获取CurrentState
           CurrentState = GetCurrentState();
           
           if (ActiveState != CurrentState)
           {
               //清理ActiveState状态的资源;
               ReleaseState(ActiveState);
               //切换当前状态未活动状态
               ActiveState = CurrentState;
           }
          
           switch(ActiveState)
           {
              case SignalA:
              {
                 //进行SignalA运算
                switch(ActiveState->m_nStep) 
                {
                   case 1:
                   //运算步骤1
                   ...
                   ActiveState->m_nStep++;
                   break;
                   
                   case 2:
                   //运算步骤2
                   ...               break;
                   
                   ...
                }          }
              break;
              case SignalB:
              {
                 //进行SignalB运算
                 ...
              }
              break;
              case SignalC:
              {
                 //进行SignalC运算
                 ...
              }
              break;
              ...
           }
       }
    }
      

  4.   

    非常感谢各位帮忙。我再解释一下,如果只是当前这个信号来不及处理,问题不是很大。我担心的是当前信号的线程占了CPU,从而影响到下一信号的处理,继而影响到下下一个信号,也就是连锁反应了。“系统负荷较大”是由于流水线速度可调,速度越快负荷越大。流水线上每个产品会触发一个信号。流水线可以调到每秒过来1个产品,也可以调到美妙过来5个、10个产品。我们当然希望能够支持越快越好。举例来说,一般产品如果正常,算法需要的时间通常会比较短一点,信号周期内完成处理问题不大。但偶尔过来一个异常产品,算法需要的时间可能会大大增加,有可能在信号周期内处理完并返回产品异常,也有可能没有处理完,这两种情况下我们都会有方法把这个产品从流水线上踢走。我担心的是,这个异常产品占用了CPU,导致下一个产品也不能在信号周期内处理完,从而也被踢走。换硬件CPU也是个办法,但用了新硬件,以后可能还是希望能够把新的硬件发挥到极限,也就是可能希望把流水线调到更快。
      

  5.   


    非常感谢!应该是个不错的方法。具体如何实现还得多学习学习。我找到下面这个帖子:
    http://topic.csdn.net/t/20030312/21/1523636.html
    应该是使用这种方法吧?
    看23楼的意思,应该是可以不用抛出异常,让线程正常结束的。不过我调试的时候,还是出现异常了。有时多加个printf打印信息,异常就没了,看样子还是有问题。不知道这方面有没有更好的资料可以学习的?
      

  6.   

    (本来想分两层楼,后来想想就合并了)原来如此啊……但每秒5个是什么速度啊,我还想建议你不用线程,而改用进程呢……
    (或者你说的是,来5个,有5个处理位,然后一次发送5个信号,创建5个线程?)另外,你处理时的算法如何,在各种极端情况下,一般都是多少毫秒处理完。
    [单个线程耗时] [多个线程并发耗时] 各种指标综合分析。
    PS: 要不你可以弄一个worker线程,专门负责申请空间,然后再这个线程内创建 Processor线程,把各种空间都传递过去,保证Processor线程连栈变量都不用,这样 TerminateThread 应该会安全点吧。这样,负责外部中断的就交给 worker线程咯。PS: 我估计,负责传送产品的系统与你现在开发的系统是完完全全的两个,不然就可以:处理完当前的,才传递下一个。
      

  7.   

    DWORD WINAPI threadFunc(LPVOID pParam);int main()
    {   HANDLE hThread;CONTEXT context;
       hThread = CreateThread(NULL,
       0,
       threadFunc,
       0,0,
       0);
     while(1)
     {
     getch();
     SuspendThread(hThread);
     context.ContextFlags=CONTEXT_CONTROL;
     GetThreadContext(hThread,&context);
     context.EFlags|=0x100;
     SetThreadContext(hThread,&context);
     ResumeThread(hThread);
     }
       return 0;
    }DWORD WINAPI threadFunc(LPVOID pParam)
    {
    d:
    __try
    {
    while(1)SwitchToThread();
    }__except(EXCEPTION_EXECUTE_HANDLER)
    {
    cout<<"sdf"<<endl;
    goto d;
    }
       return 0;
    }
      

  8.   


    非常感谢列宁同志!测试确实可以!另外受列宁同志启发,我稍微修改了一下,主要思路是在线程创建时传入CREATE_SUSPENDED,创建完后立即用CONTEXT_FULL获得线程的CONTEXT,那么以后就可以随时SetThreadContext回到线程函数的第一条代码,只要在这里加一个条件判断退出线程,就相当于能够随时退出线程,这样连异常也不要了!启动线程:
    hand = CreateThread(NULL,0,TestThread,&param,CREATE_SUSPENDED,NULL);
    Context.ContextFlags = CONTEXT_FULL;
    GetThreadContext(hand,&Context);
    ResumeThread(hand);回到线程函数的第一条代码:
    SuspendThread(hand);
    SetThreadContext(hand,&Context);
    ResumeThread(hand);