Knut is tamer



C++ extensions for readable event-driven programming


Tamer is a C++ language extension and library that simplifies event-driven programming. Functions in Tamer can block to wait for an event, then resume computation later. While one function is blocked, other functions can continue their computation. This is as easy as threaded programming, but avoids most synchronization and locking issues and generally requires less memory.

Tamer contains a preprocessor that compiles Tamer abstractions into conventional C++ code, the Tamer libraries for event-driven programming, and several examples, including a working port of the Knot web server distributed with the Capriccio threading package.

Tamer is distributed under BSD licensing terms.

Getting Started

Try reading the Events Can Make Sense paper first, then check out the code in the distribution's ex/ directory.

Why Tamer?

Tamer is a lightweight version of the Tame event-driven programming package distributed as part of SFSlite. For historical reasons, Tame follows SFS conventions, and requires a wide variety of less than documented general-purpose classes, including strings, string buffers, vectors, hash tables, linked lists, and reference counts. Better, or at least more standard, versions of many of these classes are available as part of the C++ standard library and the Boost libraries. Additionally, the Tame abstractions are layered on top of SFSlite's existing "wrap" callbacks, adding complexity and minor overhead.

Tamer is a freestanding port of the basic Tame abstractions to a standard C++ environment. Although currently less powerful than Tame and SFSlite – for example, Tamer code can block on disk I/O, a problem SFSlite can solve with RPCs, and SFSlite ships with an asynchronous DNS resolver – Tamer is much smaller and lighter weight. It was also designed to be easier to use.

If your main concern is code readability, try Tamer. If you really can never block, or would benefit from built-in RPC support, try Tame.


We are happy to accept bug reports, patches, and contributions of code, for example to improve Tamer's support for nonblocking disk I/O. Send them to


Version 1.2.2 (16.Aug.2007): Fix bugs.

Version 1.2.1 (5.Jul.2007): Change licensing terms to the BSD license.

Version 1.2.0 (13.Jun.2007): Eliminate event cancellation; after experience, it was a bad idea. Now, when the last reference to an active event is dropped, the event automatically triggers (but this is considered an error and an error message is printed). This simplifies a lot of code. (Max disagrees, and would prefer a dereferenced event to silently disappear; we will see.) ¶ event<T*>::at_trigger() replaces event<T*>::at_cancel() and event<T*>::at_complete(). tamer::unbind() replaces tamer::ignore_slot(). event<T*>::bind_all() replaces event<T*>::make_unbound().

Version 1.1.0 (5.Jun.2007): Remove tamer::fileio and tamer::at_fd_close in favor of a tamer::fd object with a better interface. ¶ Language improvements: Add "twait volatile { }" blocks. Add name mangling to closure names, allowing tamed overloaded functions. Allow tvars{} variable initialization with "type var = value". ¶ Add support for a libevent back end. When this back end is used, Tamer functions like tamer::at_fd_read() compile into libevent "struct event"s, and the Tamer driver is a wrapper for libevent’s driver. To use the Tamer native driver, set the TAMER_NOLIBEVENT environment variable. ¶ Add tamer::fun_event(), which wraps a function or function object in an event. ¶ Add event<T*>::canceler() and event<T*>::at_complete(). ¶ Bug fixes in tamer::mutex, tamer::at_time, tamer::with_timeout. ¶ Include #defines for version numbers. ¶ "make clean" fixes from Henrik Nordstrom.

Version 1.0.0 (22.May.2007): Initial release.

Eddie Kohler