孙鑫VC++视频教程关键代码在VS2010中出现问题




在孙鑫VC++6的视频教程中,第十六章:线程同步与异步套接字的例16-4代码如下:

#include <windows.h>
#include <iostream>
using namespace std;//原程序为#include <iostream.h>

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

int tickets=100;

CRITICAL_SECTION g_cs;
void main()
{
 HANDLE hThread1;
 HANDLE hThread2;
 hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
 hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
 CloseHandle(hThread1);
 CloseHandle(hThread2);

 InitializeCriticalSection(&g_cs); 
 Sleep(4000);

 DeleteCriticalSection(&g_cs);

}

DWORD WINAPI Fun1Proc( LPVOID lpParameter )
{
 while(TRUE)
 {
  EnterCriticalSection(&g_cs);
  Sleep(1);  
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
   LeaveCriticalSection(&g_cs);
  }
  else
  {
    LeaveCriticalSection(&g_cs);

    break;
  }  
 } 
 return 0;
}

DWORD WINAPI Fun2Proc( LPVOID lpParameter)

 while(TRUE)
 {
  EnterCriticalSection(&g_cs);
  Sleep(1);  
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
   LeaveCriticalSection(&g_cs);
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   break;
  }  
 } 
 return 0;
}

该段代码在VC++6.0中运行完好,没有问题,线程1和线程2交互卖票。但是当把这段程序移植到VS2010平台上之后,运行会出现问题:线程1一直在买票,线程2没有得到买票的机会。当设置相应断点之后会发现,线程2根本没有得到临界区对象的所有权,即程序根本没有进入到线程2的EnterCriticalSection(&g_cs)函数中,程序一直在线程1中运行。并且会发现,线程1的if语句中的LeaveCriticalSection(&g_cs)函数没起什么什么作用,释放临界区对象所有权之后,该所有权马上又被线程1获得,因此线程2不可能获得临界区的所有权。

修改以后的代码如下:

#include <stdafx.h>
#include <windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadProc1(LPVOID lpParameter);
DWORD WINAPI ThreadProc2(LPVOID lpParameter);

int ticket=100;

CRITICAL_SECTION g_cs;

int main()

 HANDLE handle1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
 HANDLE handle2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);


 CloseHandle(handle1);
 CloseHandle(handle2);
 InitializeCriticalSection(&g_cs);
 
 Sleep(4000);
 DeleteCriticalSection(&g_cs);
 getchar();//为使程序结果长时间显示
 return 0;
}


DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
 while(TRUE)
 {
  Sleep(1);
  EnterCriticalSection(&g_cs);  
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thread1 sale the ticket id is:"<<ticket--<<endl;
   LeaveCriticalSection(&g_cs);   
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   break;
  }  
 }
 return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
 while(TRUE)
 {
  Sleep(1);
  EnterCriticalSection(&g_cs);  
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thread2 sale the ticket id is:"<<ticket--<<endl;
   LeaveCriticalSection(&g_cs);   
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   break;
  }   
 }
 return 0;
}

主要修改的是:EnterCriticalSection(&g_cs); Sleep(1);的前后位置;将其修改为Sleep(1); EnterCriticalSection(&g_cs);

上述代码中,线程1,2先卖票先后顺序不定。并且当改变线程的sleep时间后,程序运行时卖票发生问题,不是交替卖票

或者也可以将代码修改如下:

#include <stdafx.h>
#include <windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadProc1(LPVOID lpParameter);
DWORD WINAPI ThreadProc2(LPVOID lpParameter);

int ticket=100;

CRITICAL_SECTION g_cs;

int main()

 HANDLE handle1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
 HANDLE handle2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);

 CloseHandle(handle1);
 CloseHandle(handle2);
 InitializeCriticalSection(&g_cs);
 
 Sleep(4000);
 DeleteCriticalSection(&g_cs);
 getchar();
 return 0;
}

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
 while(TRUE)
 {  
  EnterCriticalSection(&g_cs);
  Sleep(1);  
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thread1 sale the ticket id is:"<<ticket--<<endl;
   LeaveCriticalSection(&g_cs);
   Sleep(1);
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   Sleep(1);
      break;
  }  
 }
 return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
 while(TRUE)
 {  
  EnterCriticalSection(&g_cs);
  Sleep(1);  
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thread2 sale the ticket id is:"<<ticket--<<endl;
   LeaveCriticalSection(&g_cs);
   Sleep(1);
  }
  else
  {
   LeaveCriticalSection(&g_cs);
   Sleep(1);
  break;
  }   
 }
 return 0;
}

不改变EnterCriticalSection(&g_cs); Sleep(1);在源代码中前后位置,但要在if语句LeaveCriticalSection(&g_cs);的后面加上 Sleep(1); 这样线程2就能获得临界区的所有权。


注:关于有些网页上说的问题出在InitializeCriticalSection(&g_cs);这句代码上,说这段代码一定要在线程创建之前,我试验了一下,没有解决问题。InitializeCriticalSection(&g_cs);这句代码和线程没有太大的先后位置关系。

注:若改变线程的创建先后顺序,线程的执行顺序会发生变化。在第二种方法中:线程1先卖票,然后交替卖票,若先创建线程2,则线程2先卖票。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值