我编了一个多线程程序:
结构大概如下:
DWORD WINAPI thread1(LPVOID pParam){
while(1){
   操作.......
   fp=fopen("1","rb");  //打开文件1,这里有时候会阻塞
   操作.....
   fclose(fp);
   操作......
   thread1 = CreateThread(NULL, 0 ,thread2,(LPVOID)pthis,0,&tid);
   res = Valid_ID(ID_Des);   //调用一个函数
   if(res==0){                //函数返回如果是0,终止线程2 
     TerminateThread(thread2,0);
   }
}DWORD WINAPI thread2(LPVOID pParam){
操作.....
   fp=fopen("2","rb"); //打开文件2
   fread(&a,1,1,fp);
   fclose(fp);
操作.....
}
我现在的问题是,如果调用的函数返回不是0,那么就没有终止线程2,此时不断的循环调用线程1中的fopen()没有任何问题。但是如果调用的函数返回0,那么会终止线程2,此时线程1中的fopen()有时候会阻塞,即程序运行到fopen()的时候不在向下运行。
这是怎么回事???大虾们指点一下!

解决方案 »

  1.   

    在thread2中设置一个event用于检测是否退出,在TerminateThread的那句里换为设置那个event就可以了。
      

  2.   

    风请说的具体点,刚接触多线程不久,不太懂你说的意思,谢谢。
    按你说的是否能实现在thread1中终止thread2线程?
      

  3.   

    我把我的问题抽出来编了个小程序,大家可以看一下,也可以验证一下我说的问题。
    DWORD WINAPI thread1(){
      FILE *fp1;
      char type;
      short version;   unsigned long length;
         if((fp1=fopen("CRL","rb"))==NULL){
      printf("不能打开文件,请确认\"CRL\"文件是否存在\n");
      return 0;
      }
         fread(&type,1,1,fp1);
      fread(&version,2,1,fp1);
      fread(&length,4,1,fp1);
      printf"1*****************************************************************\n");
      printf("1类型:%d     版本号:%d     列表长度:%ld\n",type,version,length);
      printf("\n1显示完毕!\n") ;
      printf("1****************************************************************\n");
      fclose(fp1);
      return 1;
      
    }
      
      int main( void )  { 
      FILE *fp;
      char type;
      short version;
      unsigned long length;
      HANDLE handle1;
      int i;
      handle1=CreateThread(NULL,0,thread1,NULL,0,NULL);
      for (i=0;i<=9000;i++){  //调整循环次数可以提高fopen阻塞情况出现的频率
      ;
      }
      TerminateThread(handle1,0 );
      if((fp=fopen("CRL","rb"))==NULL){
      printf("不能打开文件,请确认\"CRL\"文件是否存在\n");
      return 0;
      }
      fread(&type,1,1,fp);
      fread(&version,2,1,fp);
      fread(&length,4,1,fp);
      printf("*****************************************************************\n");
      printf("类型:%d     版本号:%d     列表长度:%ld\n",type,version,length);
      printf("\n显示完毕!\n") ;
      printf("*****************************************************************\n");
         fclose(fp);
               return 1
    }
    大家要多运行几次才能发现fopen被阻塞的情况。
      

  4.   

    BOOL g_bStop = FALSE;
    HANDLE g_hThread1 = NULL;
    DWORD WINAPI thread1(){
      FILE *fp1;
      char type;
      short version;           if(g_bStop)
                  return 0;
      unsigned long length;
         if((fp1=fopen("CRL","rb"))==NULL){
      printf("不能打开文件,请确认\"CRL\"文件是否存在\n");
      return 0;
      }
               if(g_bStop)
               {
                  fclose(fp1);
                  return 0;
                }     fread(&type,1,1,fp1);
      fread(&version,2,1,fp1);
      fread(&length,4,1,fp1);
      printf"1*****************************************************************\n");
      printf("1类型:%d     版本号:%d     列表长度:%ld\n",type,version,length);
      printf("\n1显示完毕!\n") ;
      printf("1****************************************************************\n");
      fclose(fp1);
      return 1;
      
    }
      
      int main( void )  { 
      FILE *fp;
      char type;
      short version;
      unsigned long length;
           //  HANDLE handle1;
      int i;
               g_bStop = FALSE;
      g_hThread1=CreateThread(NULL,0,thread1,NULL,0,NULL);
      for (i=0;i<=9000;i++){  //调整循环次数可以提高fopen阻塞情况出现的频率
      ;
      }
               g_bStop = TRUE;
               WaitForSingleObject(g_hThread1, INFINITE);   
      if((fp=fopen("CRL","rb"))==NULL){
      printf("不能打开文件,请确认\"CRL\"文件是否存在\n");
      return 0;
      }
      fread(&type,1,1,fp);
      fread(&version,2,1,fp);
      fread(&length,4,1,fp);
      printf("*****************************************************************\n");
      printf("类型:%d     版本号:%d     列表长度:%ld\n",type,version,length);
      printf("\n显示完毕!\n") ;
      printf("*****************************************************************\n");
         fclose(fp);
               return 1
    }
      

  5.   

    感谢njg_jh(糨糊),我还有2个小问题:
    1.我想知道为什么使用TerminateThread()会造成fopen()阻塞,我查看帮助文件,上面只说明了 
    当线程中调用了dll或有critical section或在执行 kernel32 calls 时,调用TerminateThread()会出现问题,可为什么会导致fopen()调用阻塞呢?
    2.经过改动是可以实现终止线程2,可是由于要判断g_bstop的状态,就要不断的使用if(g_bStop)语句来进行判断,在我原来的程序里线程2比较长,这就意味着我要多次调用if(g_bStop)来检查g_bstop的状态(估计要调用10次以上,以便及时发现终止线程2的信息),这样做总感觉比较麻烦,好像没有使用TerminateThread()来的简单,有没有更好的办法来终止线程2?
      

  6.   

    楼主不要调用CreateThread函数呀,不好!
    还有使用线程的时候不要用ExitThread或TeminateThread之类的函数,C运行期库会自己调用的呀.
    我没看明白阻塞是啥意思?主线程或Thread1不执行了么?两个线程访问同一资源的话用互斥锁或critical section不好么?TerminateThread()会造成fopen()阻塞?我不信!~~     -____-!~
      

  7.   

    fopen()阻塞?线程的创建与终止对文件应该没有影响的,可能是文件已经被以独占方式打开了,或者出现了内存的覆盖
      

  8.   

    说fopen()阻塞可能是我用词不当,我的情况是运行到thread1里的fopen()函数后程序就停在这不再往下运行了!
    另外我之所以要调用TeminateThread,是因为我需要在某些情况下在thread2还没有完成的时候终止它
      

  9.   

    另外,如果我没有调用TeminateThread()终止线程2,程序运行总是正常的,只有在调用了TeminateThread()的情况下,thread1里的fopen()函数才会“阻塞”,所以我觉得是调用了TeminateThread()的原因,可是又不知道为什么会这样!
      

  10.   

    还有ashhyc(yc) 说不要使用createthread函数,为什么呢?
      

  11.   

    很复杂,大概就是应该调用C运行期库的_beginthreadex函数,如果用CreateThread那么调用C运行期库的signal函数,整个线程就会终止,即使不用sigal函数.不调用_endthreadex的话tiddata数据块就不会释放.
    所以一般都用_beginthreadex,它与_endthreadex对应啊.用CreateThread再调用_endthreadex有些不轮不类.另外,设计良好的程序重来不用TeminateThread来终止,因为被终止的线程收不到任何通知...
      

  12.   

    还有阻塞我觉的好象sleep的意思,相当于把一个线程置为等待状态,大家人为呢?
      

  13.   

    终止线程运行的最佳方法是让它的线程函数返回。但是,应该知道E x i t T h r e a d函数是Wi n d o w s用来撤消线程的函数。如果编写C / C + +代码,那么决不应该调用E x i t T h r e a d。应该使用Visual C++运行期库函数_ e n d t h r e a d e x。如果不使用M i c r o s o f t的Visual C++编译器,你的编译器供应商有它自己的E x i t T h r e a d的替代函数。不管这个替代函数是什么,都必须使用。
      

  14.   

    使用Te r m i n a t e T h r e a d,那么在拥有线程的进程终止运行之前,系统不撤消该线程的堆栈。M i c r o s o f t故意用这种方法来实现Te r m i n a t e T h r e a d。如果其他仍然正在执行的线程要引用强制撤消的线程堆栈上的值,那么其他的线程就会出现访问违规的问题。如果将已经撤消的线程的堆栈留在内存中,那么其他线程就可以继续很好地运行。
      

  15.   

    被终止线程得不到通知意味着被终止线程不能释放自己申请的空间,只能被迫的交给系统去释放.class A
    {
       public:
       A();
       ~A(); 
    }
    DWORD Thread1(void)
    {
       A a;
       Te r m i n a t e T h r e a d(0);
    }
    上面的线程不会调用析构函数.因为Te r m i n a t e T h r e a d
      

  16.   

    感谢大家的回答,现在我已经知道了调用TerminateThread()的危险性。针对我提出的2个问题:
    1.我想知道为什么使用TerminateThread()会造成fopen()阻塞?
      这个问题到现在还没搞懂,njg_jh(糨糊)说可能产生了死锁,但是怎么就死锁了呢,就我理解,
      死锁的产生一般出现在使用同步机制的情况下,可是我的程序里没有使用同步机制啊。
    2.经过改动是可以实现终止线程2,可是由于要判断g_bstop的状态,就要不断的使用if(g_bStop)语句来进行判断,在我原来的程序里线程2比较长,这就意味着我要多次调用if(g_bStop)来检查g_bstop的状态(估计要调用10次以上,以便及时发现终止线程2的信息),这样做总感觉比较麻烦,好像没有使用TerminateThread()来的简单,有没有更好的办法来终止线程2?
      关于“有没有更好的办法来终止线程2”这个问题大家还没有回答,是不是只能不停的判断g_bstop
      的值来决定是否该结束线程2?
    希望大家能帮助我搞清楚上面2个问题,谢谢!
      

  17.   

    调用g_bstop是有条件的,只能一个线程修改g_bstop值,令一个线程只能读,否则有可能使g_bstop值混乱
      

  18.   

    DWORD WINAPI thread1(LPVOID pParam){
    while(1){
       操作.......
       fp=fopen("1","rb");  //打开文件1,这里有时候会阻塞
       操作.....
       fclose(fp);
       操作......
       thread1 = CreateThread(NULL, 0 ,thread2,(LPVOID)pthis,0,&tid);
       res = Valid_ID(ID_Des);  //调用一个函数
       if(res==0){                //函数返回如果是0,终止线程2 
         TerminateThread(thread2,0);
       }
    }DWORD WINAPI thread2(LPVOID pParam){
    操作.....
       fp=fopen("2","rb"); //打开文件2
       fread(&a,1,1,fp);
       fclose(fp);
    操作.....
    }
    ===============================================================================
    主要下面代码:
       res = Valid_ID(ID_Des);  //调用一个函数
       if(res==0){                //函数返回如果是0,终止线程2 
         TerminateThread(thread2,0);
    上面不是好的代码,绝对应该避免。
    最好是重新设计吧...比如让thread执行Valid_ID.
    可以想象如果res是全局变量(或者是内核对象),不可能thread2的每条语句都执行检查res(或者是内核对象)标志,如果res = 0,那么thread2  return;
    非要这么做就用     TerminateThread(thread2,0);吧
      

  19.   

    我做了下面的程序,子线程并没有因为TerminateThread函数而出现异常.
    把hThread = (HANDLE)_beginthreadex(NULL,0,thread1,NULL,0,NULL);前面操作文件
    的语句移到TerminateThread后面也同样没有异常.
    所以TerminateThread造成阻塞是不对的呀...#include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    #include <process.h>#define FILEPATH "c:\\test.txt"
    #define BUFSIZE  32unsigned int _stdcall thread1(void * pparam)
    {
        FILE *fp;
        char cont[BUFSIZE] = "这是子进程写入的.\r\n";    printf("子线程开始操作文件.\n");
        fp = fopen(FILEPATH,"a");
        if(fp == NULL){
            printf("子线程打开文件发生错误.\n");
            return(-1);
        }    if(fwrite(cont,strlen(cont),1,fp) != 1){
            printf("子线程写文件发生错误.\n");
            return(-1);
        }
        if(fclose(fp) == -1){
            printf("子线程关闭文件发生错误.\n");
            return(-1);
        }
        printf("子线程关闭文件.\n");
        return(0);
    }int _tmain(int argc, _TCHAR* argv[])
    {
        FILE *fp;
        char cont[BUFSIZE] = "这是父进程写入的.\r\n";
        HANDLE hThread;    printf("主线程开始操作文件.\n");
        fp = fopen(FILEPATH,"a");
        if(fp == NULL){
            printf("主线程打开文件发生错误.\n");
            return(-1);
        }    if(fwrite(cont,strlen(cont),1,fp) != 1){
            printf("主线程写文件发生错误.\n");
            return(-1);
        }
        if(fclose(fp) == -1){
            printf("主线程关闭文件发生错误.\n");
            return(-1);
        }
        printf("主线程关闭文件.\n");    hThread = (HANDLE)_beginthreadex(NULL,0,thread1,NULL,0,NULL);    TerminateThread(hThread,0);    getchar();    return 0;
    }
      

  20.   

    感谢 ashhyc(yc) 这么热心,我把你的主程序改了下,你看一下,这下就会出现我说的fopen()阻塞问题了,别忘了要多运行几遍,我这运行结果是屏幕上只输出了“子线程开始操作文件”字样后程序就不往下运行了。
    int _tmain(int argc, _TCHAR* argv[])
    {
        FILE *fp;
        char cont[BUFSIZE] = "这是父进程写入的.\r\n";
        HANDLE hThread;
    int i; hThread = (HANDLE)_beginthreadex(NULL,0,thread1,NULL,0,NULL);
    for(i=0;i<100000;i++)
    ;
       TerminateThread(hThread,0);    printf("主线程开始操作文件.\n");
        fp = fopen(FILEPATH,"a");
        if(fp == NULL){
            printf("主线程打开文件发生错误.\n");
            return(-1);
        }    if(fwrite(cont,strlen(cont),1,fp) != 1){
            printf("主线程写文件发生错误.\n");
            return(-1);
        }
        if(fclose(fp) == -1){
            printf("主线程关闭文件发生错误.\n");
            return(-1);
        }
        printf("主线程关闭文件.\n");
        return 0;
    }
      

  21.   

    可能与线程的优先级有关,主线程可能系统要动态提升它的优先级。试试创建两个子进程,再试试创建不同优先级的两个子线程。
        hThread[1] = (HANDLE)_beginthreadex(NULL,0,thread2,0,0,NULL);    hThread[0] = (HANDLE)_beginthreadex(NULL,0,thread1,0,CREATE_SUSPENDED,NULL);
        SetThreadPriority(hThread[0],THREAD_PRIORITY_HIGHEST);
        ResumeThread(hThread[0]);
        CloseHandle(hThread[0]);