实现多线程同步的三种方法及示例

来源:互联网 发布:js修改class属性名称 编辑:程序博客网 时间:2024/05/19 03:24
 

http://www.programfan.com/blog/article.asp?id=23757

1、利用事件对象实现多线程的同步:

#include<windows.h>
#include<iostream.h>

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
);

int ticket=100;
HANDLE hEvent;
void main()
{
 HANDLE hThread1,hThread2;
 hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
 hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
 CloseHandle(hThread1);
 CloseHandle(hThread2);
 hEvent=CreateEvent(NULL,false,false,"ticket");
 /*该函数为创建事件对象
  *第一个参数为NULL,表示使用缺省的安全性
  *第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态
   当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态
     *第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态
  *第四个参数为事件对象的命名,当为NULL该对象为匿名对象
  */
 if(hEvent)
 {
  if(GetLastError()==ERROR_ALREADY_EXISTS)
  {
   cout<<"the Event is exists!"<<endl;
         return;
  }
  
 }
 //该函数用于设置事件对象为有信号状态
 SetEvent(hEvent);
 Sleep(4000);
 CloseHandle(hEvent);
}

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
)
{
 while(1)
 {
        WaitForSingleObject(hEvent,INFINITE);
  //ResetEvent(hEvent);
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thead1 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  SetEvent(hEvent);
 }
 return 0;
}


DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
)
{
 while(1)
 {
     WaitForSingleObject(hEvent,INFINITE);
  //ResetEvent(hEvent);
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thead2 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  SetEvent(hEvent);
  /*人工重置事件对象的做法存在两种问题:
   *当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时
   *事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程
   *都进入了受保护的语句,不能实现线程的同步。

         *当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受
   *保护的语句,不能实现线程的同步,人工重置已经不再起作用。
   */
 }
 return 0;
}

/*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
 *当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。
 *当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
 *当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。
 */
2、利用临界区实现多线程的同步:

#include<windows.h>
#include<iostream.h>

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
);

int ticket=100;
HANDLE hEvent;
void main()
{
 HANDLE hThread1,hThread2;
 hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
 hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
 CloseHandle(hThread1);
 CloseHandle(hThread2);
 hEvent=CreateEvent(NULL,false,false,"ticket");
 /*该函数为创建事件对象
  *第一个参数为NULL,表示使用缺省的安全性
  *第二个参数当为true,必须用ResetEvent人工地将事件对象设置为无信号状态
   当为false,在一个等待线程被释放后系统将事件对象自动设置为无信号状态
     *第三个参数指定事件对象的初始状态,当为true为有信号状态,否则为无信号状态
  *第四个参数为事件对象的命名,当为NULL该对象为匿名对象
  */
 if(hEvent)
 {
  if(GetLastError()==ERROR_ALREADY_EXISTS)
  {
   cout<<"the Event is exists!"<<endl;
         return;
  }
  
 }
 //该函数用于设置事件对象为有信号状态
 SetEvent(hEvent);
 Sleep(4000);
 CloseHandle(hEvent);
}

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
)
{
 while(1)
 {
        WaitForSingleObject(hEvent,INFINITE);
  //ResetEvent(hEvent);
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thead1 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  SetEvent(hEvent);
 }
 return 0;
}


DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
)
{
 while(1)
 {
     WaitForSingleObject(hEvent,INFINITE);
  //ResetEvent(hEvent);
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thead2 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  SetEvent(hEvent);
  /*人工重置事件对象的做法存在两种问题:
   *当线程1运行到WaitForSingleObject(hEvent,INFINITE)时间片用完,此时
   *事件对象仍然处于有信号状态,线程2也进入到了受保护的语句。两个线程
   *都进入了受保护的语句,不能实现线程的同步。

         *当将这个程序移植到多CPU的机子上,两个线程同时进行,双方都进入了受
   *保护的语句,不能实现线程的同步,人工重置已经不再起作用。
   */
 }
 return 0;
}

/*当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。
 *当一个线程得到人工重置事件对象,该事件对象仍然处于信号状态。
 *当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
 *当一个线程得到自动重置事件对象,该事件对象仍然处于无信号状态。
 */

3、利用互斥对象实现多线程的同步:

#include<windows.h>
#include<iostream.h>

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
);

int ticket=100;
HANDLE hMutex;
void main()
{
 HANDLE hThread1,hThread2;
 hThread1=CreateThread(NULL,0,FunProc1,NULL,0,NULL);
 hThread2=CreateThread(NULL,0,FunProc2,NULL,0,NULL);
 /*第一个参数为NULL,表示使用缺省的安全性.
  *第二个参数表示初始提交栈的大小,保留的地址空间大小是x86机子上页面大小的整数倍。
   当小于缺省提交的大小,将使用调用线程的大小。
  *第三个参数为线程运行函数的入口地址,主线程的入口函数为main.
  *第四个参数为给线程传递参数。
  *第五个参数为创建线程的控制标志.当为CREATE_SUSPENDED线程暂停,只有在调用
   ResumeThread函数时才可继续执行. 当为零的时候创建的线程立即执行。
  *第六个参数为接受线程的标识符。
      Windows NT: If this parameter is NULL, the thread identifier is not returned.
   Windows 95 and Windows 98: This parameter may not be NULL.
  */
  CloseHandle(hThread1);
  CloseHandle(hThread2);
     //关闭线程句柄可以让线程内核对象的引用计数减1,当计数为零时则释放线程内核对象
  hMutex=CreateMutex(NULL,true,"ticket");
  /*该函数为创建一个有名字的或者匿名的互斥对象。
   *第一个参数为NULL,表示使用缺省的安全性.
   *第二个参数表示互斥对象初始的拥有者。当为true,该互斥对象被调用线程所拥有。false

反之。
      *第三个参数为互斥对象的名字,如果为NULL则为匿名。
   */
  if(hMutex)
  {
   //如果互斥对象已经创建
   if(ERROR_ALREADY_EXISTS==GetLastError())
   {
    cout<<"only one instance can run!"<<endl;
    return;
   }
  }
     WaitForSingleObject(hMutex,INFINITE);
     /*这个函数将使互斥对象的计数器继续加1,此时互斥对象的计数器变为2
   *ReleaseMutex函数使互斥对象的计数器减1,此时互斥对象没有变为已通知状态
   */
  ReleaseMutex(hMutex);
  ReleaseMutex(hMutex);
  //互斥对象只有谁拥有以后才能再释放
 
  cout<<"main hThread is running!"<<endl;
  //Sleep函数是在指定时间间隔中暂停当前的线程
  Sleep(4000);     /*主线程暂停,执行副线程*/
}

DWORD WINAPI FunProc1(
  LPVOID lpParameter   // thread data
)
{
/* while(1)
 {
     //ReleaseMutex(hMutex);这里释放互斥对象不成功,先前互斥对象的线程ID是主线程,不

是线程1
        WaitForSingleObject(hMutex,INFINITE);
   *该函数为等待互斥对象,当互斥对象处于有信号状态或者在时间间隔中流逝函数返


   *第一个参数为等待对象的句柄
   *第二个参数当为INFINITE,函数永远等待下去不会返回WAIT_TIMEOUT
   *当为零时函数检测后立即返回。
   *
  if(ticket>0)
  {
   Sleep(1);//人为的交换,线程1与线程2交替进行,也会出现问题
   cout<<"thead1 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  ReleaseMutex(hMutex);
  //释放互斥对象的所有权
 }
*/
    WaitForSingleObject(hMutex,INFINITE);
 cout<<"thread1 is running!"<<endl;
 /*当进程结束后,系统会自动将互斥对象的ID设为空,计数器设为零
  *因此不调用ReleaseMutex函数互斥对象也会被释放。
  */
 return 0;
}


DWORD WINAPI FunProc2(
  LPVOID lpParameter   // thread data
)
{
/* while(1)
 {
     WaitForSingleObject(hMutex,INFINITE);
  if(ticket>0)
  {
   Sleep(1);
   cout<<"thead2 is sell ticket:"<<ticket--<<endl;
  }
  else
   break;
  ReleaseMutex(hMutex);
 }
 */
    WaitForSingleObject(hMutex,INFINITE);
 cout<<"thread1 is running!"<<endl;
 return 0;
}

 

原创粉丝点击