代码源自《VC++深入详解》第15章 “多线程”,位于第563页 - 566 页。
程序的目的是展示多线程运行的效果:
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
int index = 0;
int main()
{
HANDLE hThread1;
hThread1 = CreateThread( NULL,0,Fun1Proc,NULL,0,NULL );
CloseHandle( hThread1 );
while ( index++ < 1000 )
cout << "main thread is running." << endl;
return 0;
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while ( index++ < 1000 )
cout << "thread1 is running" << endl;
return 0;
}
运行时却发现程序崩溃了:
单击取消用OD调试:
发现程序是因为读一个0地址的内存引发了异常。在VC6中F5调试程序:
黄箭头指向的代码中对指针p解引用,而p的的值为0,这引发了异常。右击打开文件的属性,查看文件名:
是一个C语言文件,文件名为WRITE,写入的意思。我们的程序什么操作用到了写入呢?没错!用到了cout向屏幕输出字符串。
将#include 语句改为标准格式:
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
int index = 0;
int main()
{
HANDLE hThread1;
hThread1 = CreateThread( NULL,0,Fun1Proc,NULL,0,NULL );
CloseHandle( hThread1 );
while ( index++ < 1000 )
cout << "main thread is running." << endl;
return 0;
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
while ( index++ < 1000 )
cout << "thread1 is running" << endl;
return 0;
}
就可以完美运行:
然而,这是为什么呢?我们只是猜到出问题的地址,并不了解其中的原理。尝试着百度一下:
iostream.h与iostream是不同的。#include<iostream.h>是在旧的标准C++中使用。在新标准中,用#include<iostream>。iostream的意思是输入输出流。#include<iostream>是标准的C++头文件,任何符合标准的C++开发环境都有这个头文件。还要注意的是:在VC编程时要添加:using namespace std;其原因是:后缀为.h的头文件C++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,C++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。因此,当使用<iostream.h>时,相当于在C中调用库函数,使用的是全局命名空间,也就是早期的C++实现;当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。关系
<string.h>是旧的C头文件,对应的是基于char*的字符串处理函数;<string>是包装了std的C++头文件,对应的是新的string类;<cstring>是对应旧的C头文件的std版本。而<iostream.h>和<iostream>的关系,类似于<string.h>和<cstring>的关系,实现的功能是相同的,主要是是否使用命名空间std的区别。
原因就是我们使用了C++标准不支持的.h头文件,而其中的处理函数则是C语言编写的,这样基于char*的处理函数在多线程时很可能出现大问题,还是用<iostream>比较安全,也比较符合标准。