C++多线程入门

来源:互联网 发布:淘宝二手苹果ipad 编辑:程序博客网 时间:2024/06/15 18:02
       多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对多线程的理解程度从一个侧面反映了程序员的编程水平。

    其实C++语言本身并没有提供多线程机制(当然目前C++ 11新特性中,已经可以使用std::thread来创建线程了,因为还没有系统地了解过,所以这里不提了。),但Windows系统为我们提供了相关API,我们可以使用他们来进行多线程编程。创建线程的API函数:

HANDLE CreateThread(    LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD:线程安全相关的属性,常置为NULL    SIZE_T dwStackSize,//initialstacksize:新线程的初始化栈的大小,可设置为0    LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction:被线程执行的回调函数,也称为线程函数    LPVOID lpParameter,//threadargument:传入线程函数的参数,不需传递参数时为NULL    DWORD dwCreationFlags,//creationoption:控制线程创建的标志    LPDWORD lpThreadId//threadidentifier:传出参数,用于获得线程ID,如果为NULL则不返回线程ID    )BOOL WINAPI CloseHandle(HANDLE hObject); //关闭一个被打开的对象句柄


exp1:

#include "stdafx.h"#include <iostream>   #include <windows.h>   using namespace std;DWORD WINAPI Fun(LPVOID lpParamter){    for (int i = 0; i < 10; i++)    {        //cout << "A Thread Fun Display!" << endl;        cout << "A Thread Fun Display!\n";        Sleep(200);    }            return 0L;}int main(){    HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);    CloseHandle(hThread);    for (int i = 0; i < 10; i++)    {        //cout << "Main Thread Display!" << endl;//不是一气呵成,命令换行endl是一个单独的        cout << "Main Thread Display!\n";//一气呵成        Sleep(500);    }            return 0;}



     1. 这时候,正如我们预期的,正确地输出了我们想要输出的内容并且格式也是正确的。在这里,我们可以把屏幕看成是一个资源,这个资源被两个线程所共用,加入当Fun函数输出了Fun Display!后,将要输出endl(也就是清空缓冲区并换行,在这里我们可以不用理解什么是缓冲区),但此时,main函数却得到了运行的机会,此时Fun函数还没有来得及输出换行(时间片用完),就把CPU让给了main函数,而这时main函数就直接在Fun Display!后输出Main Display!。


 2.另一种情况就是“输出两个换行”,这种情况就是比如输出Main Display!并输出endl后,时间片用完,轮到子线程占用CPU,子进程上一次时间片用完时停在了Fun Display!,下一次时间片过来时,刚好开始输出endl,此时就会“输出两个换行”。


 3.那么为什么我们把实例2改成实例3就可以正确的运行呢?原因在于,多个线程虽然是并发运行的,但是有一些操作(比如输出一整段内容)是必须一气呵成的,不允许打断的,所以我们看到实例2和实例3的运行结果是不一样的。它们之间的差异就是少了endl,而多了一个换行符\n。

exp2:

#include "stdafx.h"#include <iostream>#include <windows.h>#include <mmsystem.h>  #pragma comment(lib, "winmm.lib") using namespace std; DWORD WINAPI Fun(LPVOID lpParamter){     PlaySound(TEXT("D://vvooy//em//ALARM1.WAV"), NULL, SND_FILENAME |SND_SYNC| SND_LOOP);//Absolute path Sleep(1000); return 0;}  DWORD WINAPI Fun1(LPVOID lpParamter){     PlaySound(TEXT("D://vvooy//em//ALARM1.WAV"), NULL, SND_FILENAME |SND_SYNC| SND_LOOP);//Absolute path Sleep(1000); return 0;}int main(){      int s[]={1,2,3,4,5,6};  for(int i=0;i<6;i++)  {  cout<<"s["<<i<<"]="<<s[i]<<endl;  if(s[i]<4)  {    HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);CloseHandle(hThread);cout<<"Fun display!\n"; //Sleep(1000);  }  else{HANDLE hThread = CreateThread(NULL, 0, Fun1, NULL, 0, NULL);CloseHandle(hThread);   cout<<"Fun1 display!\n"; //Sleep(1000);  }  Sleep(3000);  }      return 0;}
从这个小例子中明显看出:主函数与Fun函数同时运行,因为主函数和Fun函数执行内容的速度不同,所以主函数延迟3s是为了等待Fun函数;

exp3:

      那么,是不是exp1被注释掉的"<<endl"的代码不能正确运行吗?答案当然是否定的,下面我就来讲一下怎样才能让实例2的代码可以正确运行。这涉及到多线程的同步问题。对于一个资源被多个线程共用会导致程序的混乱,我们的解决方法是只允许一个线程拥有对共享资源的独占,这里我们用互斥量(Mutex)来进行线程同步。

0 0
原创粉丝点击