您的位置:首页 > 编程语言 > C语言/C++

C++多线程操作(火车售票系统线程同步)

2016-02-29 00:01 549 查看
注释很详细,利用了

互斥对象实现线程同步

#include <windows.h> //1.用到了WinAPI的函数

#include <iostream> //2.用到了C++标准输入输出流函数

using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter); //8.线程函数可以直接在MSDN上拷,这里是做以个函数的申明

DWORD WINAPI Fun2Proc(LPVOID lpParameter); //22.线程2的函数申明

int index=0; //14.定义一个 变量来控制循环

int tickets=100; //24.定义票的总数

HANDLE hMutex; //35.

void main() //3.main函数就是主线程的入口函数

{

HANDLE hThread1; //4.定义一个句柄,在main函数中创建一个新的线程,要创建一个线程可以利用系统给我们提供的API函数CreateThread

HANDLE hThread2; //19.创建第二个线程

hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); //5.Fun1Proc线程入口函数的地址

hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); //20将线程2的地址加入主线程中

CloseHandle(hThread1); //6.关闭线程句柄

CloseHandle(hThread2); //21.关闭线程2的句柄

//while(index++<1000) //15.当index小于1000的时候执行

//cout<<"main thread is running!"<<endl; //7.输出一行字,表明是主线程在运行

//Sleep(10); //13.让主线程停止执行,即这10毫秒内主线程放弃执行的权利,运行发现两个都运行了,下面要让主线程和线程1不断的交替运行,我们可以做一个循环

//16.这个时候因为主线程执行的时间较长,这个时间已经大于了系统分配给主线程的时间片,所以就有执行其他线程的机会了

//hMutex=CreateMutex(NULL,FALSE,NULL); //36.创建互斥对象,FALSE(表示主线程不拥有) 将它的ID设置为空,即此时谁都没有拥有这个线程ID,系统会自动设为0,处于有信号状态,继续向下执行,

//42.如果这里设置为TRUE,那么主线程拥有互斥对象此时计数器记录为1,调用一个ReleaseMutex释放之后计数器又记录为0,

//43.此时信号处于可用状态,其他的线程可以使用,每申请一次就加1,释放就减1,为0则可用

//44.如果我们将最后一个NULL(没有名字)去掉,并且给这个互斥对象取名

hMutex=CreateMutex(NULL,TRUE,"tickets"); //45.给这个互斥对象取名 将中间的设置为TRUE

if(hMutex) //46.判断对象是否已经存在,如果存在就执行下面的

if(ERROR_ALREADY_EXISTS==GetLastError()) //47.判断实例是否正在运行

{

cout<<"Only one instance can run!"<<endl;

return;

}

ReleaseMutex(hMutex); //48.释放主线程互斥对象,在10s内连开多个实例只有第一个可以顺利运行,这就是互斥对象的用法

Sleep(10000); //27.让主线程睡眠1秒,这个时间必须设置合理,不然线程1、2没运行完就关了进程

}

DWORD WINAPI Fun1Proc(LPVOID lpParameter) //9.实现函数部分

{

/*while(index++<1000) //17.index小于1000的时候执行,执行之后发现它们是交替运行的,说明是按时间片来的,这是单CUP下,如果是双CUP就可以真正的额实现同时运行了

cout<<"thread1 is running!"<<endl;*/

while(TRUE) //24.在线程1里做循环,

{

WaitForSingleObject(hMutex,INFINITE); //37.这个函数是等待接受互斥对象的信号,一旦有信息进入,就向下执行,否则一直等待 因为设置的是这个模式(INFINIT)

if(tickets>0)

{

Sleep(1); //30.Test!

cout<<"Thread1 sell tickets:"<<tickets--<<endl;//25.满足条件就打印这行,表明执行了 线程1

}

else

break;

ReleaseMutex(hMutex); //38.执行完成之后,交出信号,这时系统又将线程ID设置为空,如果线程1的时间片没完,就继续执行线程1,如果线程1执行过程中时间片就到了,这时就跳到执行线程2

//39.但是由于线程1的信号没有交出,所以互斥对象的线程ID还是线程1的,线程2没有得到信号会一直等待,直到时间片结束,转到线程1,执行完成,释放线程ID

}

return 0; //10.要求返回值

} //11.这样运行之后发现只有主线程在运行线程1并不运行,这主要是当主线程运行完之后就将进程给关了,进程关了,其他的线程就没有运行的机会就关闭了

//12.可以让主线程执行完就睡眠一会儿,这样其他的线程就可以执行了

//18.下面来模拟火车站的售票系统,显然它是一个多线程的系统,我们在增加一个线程2

DWORD WINAPI Fun2Proc(LPVOID lpParameter) //23.线程2的函数实现部分

{

while(TRUE) //26.同样作循环,还有一个问题,在执行这两个线程的时候要保证主线程运行,注意不要让主线程做空循环,这样浪费CPU时间,效率不高,让他睡眠比较好

{

WaitForSingleObject(hMutex,INFINITE); //40.等待互斥对象得信号,没有得到信号一直等待,直到时间片完成

if(tickets>0)

{

Sleep(1); //31.Test!

cout<<"Thread2 sell tickets:"<<tickets--<<endl;

}

else

break;

ReleaseMutex(hMutex); //41.释放互斥对象,注意是“谁拥有谁释放”,这样执行之后问题就解决了,多线程访问同一资源的时候经常出现资源重复,这时就要用到互斥对象了,在一个进程正在访问的时候不允许另一个访问

}

return 0; //28.还有一个问题,如果线程1执行卖85张的时候,时间片到了,就会转到线程2中执行,这时线程2中,线程2 就卖出了第85张,过一段时间候线程2的时间到了,

//29.又转到线程1中,线程1继续卖它的85张,这样就可能卖出两张相同的票号的票,这种情况最容易发生在转换时间片的时候,还有可能出第0张票,我们可以将循环睡眠一段时间看看

} //32.这是多线程访问同一种资源造成的,可以看到又很多的重复,还有0也被卖出了,这是不行的!,如果我们能做线程的同步就能解决了

//33.构建一个互斥对象来解决这个问题 CreateMutex函数 互斥对象属于内核对象它能确保线程拥有对单个资源的互斥访问权,它包含一个使用数量、一个线程ID、一个计数器。ID用于标识系统中的哪个线程当前拥有互斥对象

//34.计数器用于指明该线程拥有互斥对象的次数。CreateMutex返回一个句柄

转载出处:http://dongxiang-2007.blog.sohu.com/112078796.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: