win32多线程-异步过程调用(asynchronous Procedure Calls, APCs)

时间:2022-09-18 22:01:33

使用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)的更多相关文章

  1. win32多线程-异步&lpar;asynchronous&rpar; I&sol;O

    I/O设备是个慢速设备,无论打印机.调制解调器,甚至硬盘,与CPU相比都奇慢无比,坐下来干等I/O的完成是一件不甚明智事情. 异步(asynchronous) I/O在win32多线程程序设计中被称为 ...

  2. 深入浅出Win32多线程程序设计之基本概念

    一.深入浅出Win32多线程程序设计之基本概念[转] 引言 从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最优秀的程序员也只能通过驻留内存的方式实现所谓 ...

  3. APC -- Asynchronous Procedure Call 异步过程调用

    异步过程调用(APC -- Asynchronous Procedure Call )是一种与常用的和简单的同步对象不同的一种同步机制. 我们在我们线程里使用基本的同步对象如MUTEX去通知其它线程, ...

  4. 多线程学习:win32多线程编程基本概念&lpar;转&rpar;

    一.定义: 1.进程和线程的区别 进程:是程序的执行过程,具有动态性,即运行的程序就叫进程,不运行就叫程序 ,每个进程包含一到多个线程.线程:系统中的最小执行单元,同一进程中有多个线程,线程可以共享资 ...

  5. AsyncCalls – Asynchronous function calls

    AsyncCalls – Asynchronous function callsWith AsyncCalls you can execute multiple functions at the sa ...

  6. Win32多线程编程&lpar;1&rpar; — 基础概念篇

      内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...

  7. 由《win32多线程程序设计》临界区的问题所想

    之前看侯捷翻译的<win32多线程程序设计>中关于线程同步中的临界区问题,其中举得例子是对链表的操作.死锁的问题是对一个Swaplist函数的问题,现列举代码如下: void SwapLi ...

  8. Win32多线程编程&lpar;3&rpar; — 线程同步与通信

      一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...

  9. Win32 多线程的创建方法和基本使用

    Win32多线程的创建方法主要有: (1)CreateThread() (2)_beginthread()&&_beginthreadex() (3)AfxBeginThread() ...

随机推荐

  1. MS SQL中使用UPDATE &period;&period;&period; INNER JOIN &period;&period;&period;

    昨天的SQL编程中,有使用到一个方法,就是把一个表某一字段更新至另一个表的字段中去. 实现这个方法,Insus.NET有尝试了几个方法,下面一一分享出来,让大家参考参考. 下面的数据只是模拟了,形式与 ...

  2. XmlSpy &sol; XSD 以及 验证

    很早以前看过一句话:“XML就象空气”,在企业应用开发中XML是一个重要的数据交换标准.而XSD则可以用来校验XML的数据格式是否正确. 一个典型的XSD文件如下: <?xml version= ...

  3. python读取xml文件

    关于python读取xml文章很多,但大多文章都是贴一个xml文件,然后再贴个处理文件的代码.这样并不利于初学者的学习,希望这篇文章可以更通俗易懂的教如何使用python 来读取xml 文件. 什么是 ...

  4. jqGrid根据ID获取行号

    根据行号获取ID $('#grid').getCell(rownumber,'id') 根据ID获取行号 $('#' + rowid)[0].rowIndex

  5. BZOJ 4127 Abs 解题报告

    这个题感觉很厉害的样子.. 首先我们注意到一点:每次加的 $d$ 都是非负的. 那么就说明一个数只可能从负数变成非负数并且只会变一次. 所以我们就可以暴力地去改变一个数的正负情况. 然后我们就可以用树 ...

  6. oracle数据库创建表&comma;序列及添加代码案例

    create table cdpt( id number(6), name varchar2(30), constraint pk_id primary key(id) ); 更改数据库的“延迟段创建 ...

  7. java时间格式转化(毫秒 to 00&colon;00)

    把秒数转换为%d:%02d:%02d 格式 private String stringForTime(int timeSec) { int totalSeconds = timeSec; int se ...

  8. JDK开发环境配置

    1. 新建 -> 变量名“JAVA_HOME”, 变量值“C:\Program Files\Java\jdk1.8.0_112”(即JDK的安装路径) 2. 编辑 -> 变量名“Path” ...

  9. windows2012 IIS部署GeoTrust证书踩过的坑。 视频测试可用 IIS 证书导入

    证书导入方式 https://wenku.baidu.com/view/3504f29a55270722192ef78a.html https://www.cnblogs.com/jackrebel/ ...

  10. openstack-----各种系统镜像制作

    本章内容     1.centos镜像制作 2.windows镜像制作 3.ubunt镜像制作 一.centos7镜像制作 1.检查系统是否支持kvm: egrep "(vmx|svm)&q ...