Using asynchronous I/O

The D standard library does not include asynchronous I/O functions, but we can still use them by calling C functions or with third-party libraries.

How to do it…

We will execute the following steps to use asynchronous I/O:

  1. Find a C API you like, either the operating system functions or a third-party library such as libuv or libevent, bindings to which can be found at http://code.dlang.org/.
  2. Use the C functions instead of the Phobos functions.

Here's an example of how to get an asynchronous input from a text file on Windows using the Win32 API:

import core.sys.windows.windows; // basic Windows headers
import std.conv;

 // Not all necessary functions are defined in core.sys.windows.windows
 // but that's never a dealbreaker: we can just define the prototypes ourselves
// ReadFileEx is specialized for asynchronous reading
  extern(Windows)
    BOOL ReadFileEx(HANDLE, LPVOID, DWORD, OVERLAPPED*, void*);
// SleepEx will pause the program, allowing our async handler to be called when the data is ready
  extern(Windows)
    DWORD SleepEx(DWORD, BOOL);
// This function will be called when the operation is complete
extern(Windows) void readCallback(DWORD errorCode, DWORD numberOfBytes, OVERLAPPED* overlapped) {
  // hEvent carries user-defined data. We load it with a pointer to the buffer below.
  auto data = (cast(ubyte*) overlapped.hEvent)[0 .. numberOfBytes];
  import std.stdio;
  writeln("Received: ", cast(string) data);
  // we may issue another read here to get more data
}

void main() {
   // We need to open the file with the Windows API too, so we can set the
  // required FILE_FLAG_OVERLAPPED for asynchronous access
  auto handle = CreateFileA("test.txt", GENERIC_READ, 0, null, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, null);
  if(handle is null) throw new Exception("Couldn't open file.");
  scope(exit) CloseHandle(handle); // always cleanup C resources with scope guards

  OVERLAPPED overlapped;
  ubyte[1024] buffer;
  overlapped.hEvent = buffer.ptr; // This is allowed to be user-defined data, we'll fill it with a pointer to the buffer for use in the callback
  // issue the async read request
  if(ReadFileEx(handle, buffer.ptr, buffer.length, &overlapped, &readCallback) == 0)
    throw new Exception("ReadFileEx failed " ~ to!string(GetLastError()));

  /* Do other things while the operating system loads the data for us…. */

  SleepEx(500, true); // wait for the operation to complete
}

If you create a file called test.txt and then run the program, it will display its contents.

How it works…

Since D has full access to C libraries and operating system APIs, we can use functionality that is not yet available in Phobos when we need it. Asynchronous I/O is an example where this is necessary. The example is virtually identical to what you might see in an example in the C language.

On Windows, a flag must be set when the handle is created to enable asynchronous operations (called overlapped operations in the Microsoft documentation). On Posix, a flag may be set with fnctl after the file is opened, or you may use an event loop that triggers on file readiness to avoid blocking operations.

These operations require full access to the file handle, which limits the amount of Phobos calls you can use. For example, std.process.pipeProcess conveniently creates the pipes for you, but that precludes setting the overlapped flag. If you want to use asynchronous I/O on a pipe to communicate with another process, it will be necessary to perform all the operations yourself at the operating system API level. (Indeed, on Windows, you cannot even use the CreatePipe function that the std.process implementation uses to create the pipes because it does not allow you to set the overlapped flag either; you must use the lower-level CreateNamedPipe function instead.)

In some cases, you can create a Phobos object from an operating system handle. For example, you can create std.socket.Socket from an existing low-level handle, but in most cases, you are on your own to write the code as you would in C. When in doubt, you can search the Internet for C asynchronous I/O documentation and examples and apply that same knowledge to D.

See also

  • The website http://code.dlang.org/ has wrappers for C libraries to ease the use of cross-platform asynchronous I/O
  • To see the D framework that uses asynchronous I/O internally, visit http://vibed.org/
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.83.176