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

《VC++深入详解》学习笔记[13]——第16章 线程同步与异步套接字编程

2011-12-12 08:25 274 查看
第16章 线程同步与异步套接字编程
1.事件对象

事件对象与互斥对象一样也属于内核对象。事件对象有两种不同的类型:

人工重置的事件对象:当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程。当线程等待到该对象的所有权之后,需要显示地调用ResetEvent函数手动将该事件对象设为无信号状态;

自动重置的事件对象:当一个自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个线程变为可调度线程。当线程得到该对象的所有权之后,系统会自动将该对象设置为无信号状态。

为了实现线程间的同步,不应该使用人工重置的事件对象,而应该使用自动重置的事件对象。

代码分析:

#include <windows.h>

#include <iostream.h>

int ticket=100;

HANDLE g_hEvent;//保存事件对象句柄

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

void main()

{

HANDLE thread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

HANDLE thread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

CloseHandle(thread1);

CloseHandle(thread2);

//创建事件对象,可用命名事件对象来控制只运行一个实例

g_hEvent=CreateEvent(NULL,

FALSE, //TRUE人工重置,FALSE 自动重置

FALSE, //初始化状态,TURE信号状态,FALSE非信号状态

"tickets"); //事件对象命名,NULL表示匿名

if(g_hEvent)

{

if(ERROR_ALREADY_EXISTS == GetLastError())

{

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

return;

}

}

SetEvent(g_hEvent);//将事件设置为有信号状态

Sleep(4000);

CloseHandle(g_hEvent);

}

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

WaitForSingleObject(g_hEvent,INFINITE);

while(ticket)

{

cout<<"thread1 sells : "<<ticket--<<endl;

Sleep(1);

SetEvent(g_hEvent);

}

return 0;

}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

WaitForSingleObject(g_hEvent,INFINITE);

while(ticket)

{

cout<<"thread2 sells : "<<ticket--<<endl;

Sleep(1);

SetEvent(g_hEvent);

}

return 0;

}

2.关键代码段

关键代码段也称为临界区,工作在用户方式下。它是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。通常把多线程中访问同一种资源的那部分代码当做关键代码段。

代码分析:

#include "windows.h"

#include "iostream.h"

int ticket=100;

//HANDLE g_hEvent;

DWORD WINAPI Fun1Proc(LPVOID lpParameter);

DWORD WINAPI Fun2Proc(LPVOID lpParameter);

CRITICAL_SECTION g_cs;//临界区对象

void main()

{

HANDLE thread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);

HANDLE thread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);

CloseHandle(thread1);

CloseHandle(thread2);

//初始化一个临界区对象

InitializeCriticalSection(&g_cs);

Sleep(4000);

// 释放一个没有被占有的临界区对象的所有资源

DeleteCriticalSection(&g_cs);

}

DWORD WINAPI Fun1Proc(LPVOID lpParameter)

{

while(TRUE)

{

EnterCriticalSection(&g_cs);//等待临界区对象的所有权

//当调用线程赋予所有权进,本函数返回

// 如果一直没能等待到,那么导致线程暂停

if(ticket>0)

{

cout<<"thread1 sells : "<<ticket--<<endl;

Sleep(1);

}

else break;

LeaveCriticalSection(&g_cs);//释放指定临界区对象所有权

}

return 0;

}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)

{

while(TRUE)

{

EnterCriticalSection(&g_cs);

if(ticket>0)

{

cout<<"thread2 sells : "<<ticket--<<endl;

Sleep(1);

}

else break;

LeaveCriticalSection(&g_cs);

}

return 0;

}

死锁:如果线程1拥有了临界区对象A,等待临界区对象B的拥有权,线程二拥有了临界区对象B,等待临界区对象A的拥有权,这样就造成了死锁。

互斥对象、事件对象与关键代码段的比较:

1.互斥对象和事件对象都属于内核对象,利用内核对象进行线程同步时,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。

2.关键代码段工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。

基于消息的异步套接字:

Windows套接字在两种模式下执行IO操作:阻塞模式和非阻塞模式。Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存储策略,即采用非阻塞方式实现网络应用程序。异步选择函数WSAAsyncSelect提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序响应的窗口函数将收到一个消息,消息中指示了发生的网络事件以及一些相关信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: