win32多线程-异步过程调用(asynchronous Procedure Calls, APCs)
使用overlapped I/O并搭配event对象-----win32多线程-异步(asynchronous) I/O事例,会产生两个基础性问题。
第一个问题是,使用WaitForMultipleObjects(),你只能等待最多达MAXIMUM_WAIT_OBJECTS个对象,在Windows NT中此值最大为64。
第二个问题是,你必须不断根据“那一个handle被激发”而计算如何反应。你必须有一个分派表格(dispatch table)和WaitForMultipleObjects()的handles数组结合起来。
这两个问题可以靠一个所谓的异步过程调用(asynchronous Procedure Calls, APCs)解决,只要使用“Ex”版的ReadFile()和WriteFile(),你就可以调用这个机制。这两个函数允许你指定一个额外的参数,是一个callback函数,这个callback函数被称为I/O completion routine,因为系统是在某一个特别的overlapped I/O操作完成之后调用它。
异步过程调用事例:
/*
* IoByAPC.c
*
* Sample code for Multithreading Applications in Win32
* This is from Chapter 6, Listing 6-3
*
* Demonstrates how to use APC's (asynchronous
* procedure calls) instead of signaled objects
* to service multiple outstanding overlapped
* operations on a file.
*/ #define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "MtVerify.h" //
// Constants
//
#define MAX_REQUESTS 5
#define READ_SIZE 512
#define MAX_TRY_COUNT 5 //
// Function prototypes
//
void CheckOsVersion();
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount); //
// Global variables
// // Need a single event object so we know when all I/O is finished
HANDLE ghEvent;
// Keep track of each individual I/O operation
OVERLAPPED gOverlapped[MAX_REQUESTS];
// Handle to the file of interest.
HANDLE ghFile;
// Need a place to put all this data
char gBuffers[MAX_REQUESTS][READ_SIZE];
int nCompletionCount; /*
* I/O Completion routine gets called
* when app is alertable (in WaitForSingleObjectEx)
* and an overlapped I/O operation has completed.
*/
VOID WINAPI FileIOCompletionRoutine(
DWORD dwErrorCode, // completion code
DWORD dwNumberOfBytesTransfered, // number of bytes transferred
LPOVERLAPPED lpOverlapped // pointer to structure with I/O information
)
{
// The event handle is really the user defined data
int nIndex = (int)(lpOverlapped->hEvent);
printf("Read #%d returned %d. %d bytes were read.\n",
nIndex,
dwErrorCode,
dwNumberOfBytesTransfered); if (++nCompletionCount == MAX_REQUESTS)
SetEvent(ghEvent); // Cause the wait to terminate
} int main()
{
int i;
char szPath[MAX_PATH]; CheckOsVersion(); // Need to know when to stop
MTVERIFY(
ghEvent = CreateEvent(
NULL, // No security
TRUE, // Manual reset - extremely important!
FALSE, // Initially set Event to non-signaled state
NULL // No name
)
); GetWindowsDirectory(szPath, sizeof(szPath));
strcat(szPath, "\\WINHLP32.EXE");
// Open the file for overlapped reads
ghFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (ghFile == INVALID_HANDLE_VALUE)
{
printf("Could not open %s\n", szPath);
return -1;
} // Queue up a few requests
for (i=0; i<MAX_REQUESTS; i++)
{
// Read some bytes every few K
QueueRequest(i, i*16384, READ_SIZE);
} printf("QUEUED!!\n"); // Wait for all the operations to complete.
for (;;)
{
DWORD rc;
rc = WaitForSingleObjectEx(ghEvent, INFINITE, TRUE );
if (rc == WAIT_OBJECT_0)
break;
MTVERIFY(rc == WAIT_IO_COMPLETION);
} CloseHandle(ghFile); getchar();
return EXIT_SUCCESS;
} /*
* Call ReadFileEx to start an overlapped request.
* Make sure we handle errors that are recoverable.
*/
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount)
{
int i;
BOOL rc;
DWORD err; gOverlapped[nIndex].hEvent = (HANDLE)nIndex;
gOverlapped[nIndex].Offset = dwLocation; for (i=0; i<MAX_TRY_COUNT; i++)
{
rc = ReadFileEx(
ghFile,
gBuffers[nIndex],
dwAmount,
&gOverlapped[nIndex],
FileIOCompletionRoutine
); // Handle success
if (rc)
{
// asynchronous i/o is still in progress
printf("Read #%d queued for overlapped I/O.\n", nIndex);
return TRUE;
} err = GetLastError(); // Handle recoverable error
if ( err == ERROR_INVALID_USER_BUFFER ||
err == ERROR_NOT_ENOUGH_QUOTA ||
err == ERROR_NOT_ENOUGH_MEMORY )
{
Sleep(50); // Wait around and try later
continue;
} // Give up on fatal error.
break;
} printf("ReadFileEx failed.\n");
return -1;
} //
// Make sure we are running under an operating
// system that supports overlapped I/O to files.
//
void CheckOsVersion()
{
OSVERSIONINFO ver;
BOOL bResult; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); bResult = GetVersionEx((LPOSVERSIONINFO) &ver); if ( (!bResult) ||
(ver.dwPlatformId != VER_PLATFORM_WIN32_NT) )
{
fprintf(stderr, "IoByAPC must be run under Windows NT.\n");
exit(EXIT_FAILURE);
} }
win32多线程-异步过程调用(asynchronous Procedure Calls, APCs)的更多相关文章
- win32多线程-异步(asynchronous) I/O
I/O设备是个慢速设备,无论打印机.调制解调器,甚至硬盘,与CPU相比都奇慢无比,坐下来干等I/O的完成是一件不甚明智事情. 异步(asynchronous) I/O在win32多线程程序设计中被称为 ...
- 深入浅出Win32多线程程序设计之基本概念
一.深入浅出Win32多线程程序设计之基本概念[转] 引言 从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最优秀的程序员也只能通过驻留内存的方式实现所谓 ...
- APC -- Asynchronous Procedure Call 异步过程调用
异步过程调用(APC -- Asynchronous Procedure Call )是一种与常用的和简单的同步对象不同的一种同步机制. 我们在我们线程里使用基本的同步对象如MUTEX去通知其它线程, ...
- 多线程学习:win32多线程编程基本概念(转)
一.定义: 1.进程和线程的区别 进程:是程序的执行过程,具有动态性,即运行的程序就叫进程,不运行就叫程序 ,每个进程包含一到多个线程.线程:系统中的最小执行单元,同一进程中有多个线程,线程可以共享资 ...
- AsyncCalls – Asynchronous function calls
AsyncCalls – Asynchronous function callsWith AsyncCalls you can execute multiple functions at the sa ...
- Win32多线程编程(1) — 基础概念篇
内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...
- 由《win32多线程程序设计》临界区的问题所想
之前看侯捷翻译的<win32多线程程序设计>中关于线程同步中的临界区问题,其中举得例子是对链表的操作.死锁的问题是对一个Swaplist函数的问题,现列举代码如下: void SwapLi ...
- Win32多线程编程(3) — 线程同步与通信
一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...
- Win32 多线程的创建方法和基本使用
Win32多线程的创建方法主要有: (1)CreateThread() (2)_beginthread()&&_beginthreadex() (3)AfxBeginThread() ...
随机推荐
- int 价值型追记-time
一个 30 M 的int号码值一次性保存.和读取一次,避免保存为char 种类,进行格转变,格转换时间是非常耗时. #include <iostream> #include <fst ...
- java_部署jar
javaw -ms100m -mx256m -jar MyApp.jar 上面指定了使用最小100M最大256M内存. 4)如果main函数要带参数 java -mss10m -mx300m -jar ...
- mysql_常用命令
1: 以指定编码创建数据库 CREATE DATABASE `search_data` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
- 基OOP知识
从今天开始,我开始总结GAO还通高老师<android道路的建筑师>,尝试一个星期写三个博客. 相对而言.看到这篇文章有点速度比你可以观看视频,刚才看的视频是更具体的.假设有兴趣,跟着我去 ...
- SharePoint 2013 搜索SharePoint 特定列和特定文档(自己定义搜索)
SharePoint 2013 搜索SharePoint 特定列和特定文档 1,操作步骤和图例,因语言和版本号的不同 我尽量使用抓图方式. 2. In Central Administration, ...
- 8.无法訪问developer.android.com的解决方式。
问题:无法訪问developer.android.com,就无法知道Android的最新信息. 解决的方法:寻找国外的代理ip,比方http://www.xici.net.co/上面的国外代理ip. ...
- 使用Jenkins来构建Docker容器
使用Jenkins来构建Docker容器(Ubuntu 14.04) 当开发更新了代码,提交到Gitlab上,然后由测试人员触发Jenkins,于是一个应用的新版本就被构建了.听起来貌似很简单,dua ...
- CentOs Linux 常见命令
整理一些常用的命令(持续更新): 查看端口是否开启: netstat -an | grep prot (查看是否打开23端口) |:通道的意思,grep是指查看当前字符所在的行 LINUX通过下面的命 ...
- 如何查看IC卡燃气表读数和剩余量?
如今新建的楼房都是使用IC卡燃气表,拿到房子入住时也没有见到IC卡燃气表的使用说明书.非常多人可能为此而苦恼.这里就讲一下怎样查看IC卡燃气表读数及剩余金额. 产品外观 可选功能 watermark/ ...
- ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!)
原文:ORACLE PL/SQL编程之六:把过程与函数说透(穷追猛打,把根儿都拔起!) ORACLE PL/SQL编程之六: 把过程与函数说透(穷追猛打,把根儿都拔起!) 继上篇:ORACLE P ...