Horsing around with the C++ programming language Copyright Edd Dawson Sat, 15 Dec 2012 00:00:01 GMT 720 Faster Windows Events Windows Events have one capability not offered by any other synchronization primitive that I've encountered: when configured for 'manual reset', they have the ability to awaken multiple threads with a single kernel call. A condition variable broadcast can also do this, but each thread has to acquire and release a shared mutex once awoken, creating an unnecessary bottleneck. Used in this way, events are useful for implementing things like futures that cater for multiple simultaneous waiters, such as std::shared_future<>. Here, the event is used to keep threads at bay until the future's value materializes. However, because events are represented by Windows HANDLEs in user-space code, any operation on an event has to transition to the kernel, even if it's only asking whether or not the event is set (or signalled). Here I'll describe how we can add fast paths to all event operations using atomic operations and provide some simple benchmarks to illustrate the improvements. Sat, 15 Dec 2012 00:00:01 GMT Ruminations on protected Or at the very least, some cheap one-liners. protected is far closer to public than it is to private.In fact the only difference between protected and public is target audienceprotected is not for making things a bit tediouser to get attediouser is now a wordUsing protected just in case makes less sense than using private just in caseprotected is a code-smell. ¡¡CONTROVERSIAL!! Sun, 09 Dec 2012 00:00:01 GMT GPL-free symbol lookup code for MinGW I've just published a new repository on bitbucket for a library called dbg. It contains a collection of high-level assert macros, code for call frame collection, symbol lookup and exception tracebacks. I've already published a similar library, stack_trace, but this one contains GPL-free code for symbol lookup on MinGW targets. This is achieved by skimming the DWARF debug information directly, rather than going through libbfd. dbg, as is the case with the majority of my code, is licensed under the Boost Software License, making it somewhat more friendly for use in closed-source software. I mention it here because I know from email correspondance that a number of people were interested in seeing this. Sun, 09 Sep 2012 00:00:01 GMT The sad state of pthread_mutex_t on OS X Recently I came across the concept of a benaphore and decided to play around with it. A benaphore is a kind of mutex that should in theory be faster in very-low-contention scenarios. The implementation is very simple:class benaphore : uncopyable { public: benaphore() : sema(0 /* initial value */), count(0) { } void lock() { if (++count > 1) sema.acquire(); } void unlock() { if (--count > 0) sema.release(); } private: semaphore sema atomic<uint32_t> count; }; When there's no contention, locking and unlocking is as simple as incrementing and decrementing a atomic integer, potentially making it suitable for the protection of rarely accessed resources. In reality it shouldn't be needed, as any decent mutex implementation is going to have a fast-path that avoids interaction with the kernel, anyway. But out of curiosity I benchmarked it against a pthread_mutex_t on OS X. Sat, 25 Aug 2012 00:00:01 GMT Another use for explicit vtables In my previous post I outlined a technique whereby coupling could be reduced by way of creating a pseudo-vtable. I've since realised that this technique can also be used to help create an efficient representation for polymorphic types with value semantics. Consider this base class, which we might use as the root of a polymorphic class hierarchy in a computer game:struct monster { virtual ~monster(); virtual void attack(player &target); }; Such polymorphic hierarchies will typically imply dynamic allocation somewhere along the line. For example, we typically won't create a std::vector<monster> because we can't store derived monster objects by value in containers without slicing. Instead, we'll have to do something like keep a container of (smart) pointers, or use a smart container such as boost::ptr_vector<monster>, which in turn means we'll probably have to allocate our derived monster objects on the heap. The large number of small allocations implied by this approach can be detrimental in a number of ways; some of the locality benefits we may have got with a vector<> have been lostdepending on the quality and characteristics of our allocator due to the monsters now being dotted around the heap. The allocations themselves can be detrimental to performance, especially if frequent. Contention within allocation routines running in multi-threaded applications can exacerbate this problem. Let's see how we might avoid these problems by adapting the explicit vtables technique described previously. Tue, 24 Apr 2012 00:00:01 GMT Nifty little lock class Happy new(?) year! Ok, ok, so I haven't written in a while. I've been meaning to finish of the series on undo/redo for some time now. Hopefully I'll get that put to bed at some point, but in the meantime I'll try to get the ball rolling with something smaller. If you've written any code that uses low-level threading primitives such as mutexes, you'll likely/hopefully be aware of the 'scoped-locking' idiom. In short, it looks something like this:void some_function(mutex &m) { lock lk(m); // calls m.acquire(); // ... // lk's destructor calls m.release(). } It ensures that a lock is always released, regardless of whether the scope is left via a return statement, or due to an exception. This is a nice way to statically ensure that you don't accidentally leave a mutex in an acquired stateMany will likely recognise this as an instance of the RAII idiom. But it's quite often the case that a threading library will offer a selection of different mutex types to choose from. Each mutex will offer the same core interface: acquire() and release(). What typically happens, therefore, is that the lock class is becomes a template with the type of mutex as a template-parameter. This in turn means that the creation of the lock object can take a bit more typing than we might like:void some_function(recursive_mutex &m) { lock<recursive_mutex> lk(m); // ... } On its own that's not too bad, but any function that once took a reference to a lock object as a parameter may now have to become a template function in order to accept arbitrary lock types, possibly increasing compile times as a side-effect. This is the case with some of the methods on boost::condition_variable, for example. Here's a simple but cunning technique for overcoming these problems: Thu, 08 Mar 2012 00:00:01 GMT _GLIBCXX_DEBUG is broken on Apple's GCC 4.2 Upgraded to Lion recently and hit this issue rather quickly. Just slapping it here for those Googling around the issue. The definition of _GLIBCXX_DEBUG seems to affect the C++ standard streams particularly badly. More: EDIT: specifically it appears to occur when building against the 10.6 and 10.7 SDKs I've also had some trouble with the XCode 4's ar and the compiler also issues lots of annoying warnings about the inability to "add line info to anonymous symbol"s. Somewhat underwhelmed by both Lion and XCode 4's tools so far :/ Thu, 11 Aug 2011 00:00:01 GMT Undo/redo part 3: combining actions Previously in this undo/redo series we've looked at: how to set up a basic action interface and a simple undo_stack classhow exception safety guarantees of actions affect the undo_stack's implementationIn this episode, I'd like to look at how to efficiently combine two or more actions in to a single compound action and why we might want to do so. I guess this topic wanders back in to the realms of what others articles have discussed before when looking at undo/redo. We'll see however, that exception safety will come back in to the picture briefly, which is something all other articles I've read seem to neglect. Tue, 08 Feb 2011 00:00:01 GMT Strange GCC error: expected unqualified-id before ‘OTHER’ token A brief interlude in the undo/redo series. Just posting this here so that Google can index the answer. Today, we were seeing a strange error coming from one of our source files when compiled with Apple's g++ 4.0.1: error: expected unqualified-id before ‘OTHER’ tokenThe problem here is that the file has a byte order mark, which g++ doesn't seem to like (at least this not flavour of g++, anyway). If you happen to be using Vim, this should fix it, I think: :setlocal nobomb :w Fri, 28 Jan 2011 00:00:01 GMT Undo/redo part 2: exception safety Ok, so on with the second installment of the N-part series on undo/redo mechanisms. Last time we introduced the action base class and an elementary undo_stack. I claimed that those were the easy bits, or at the very least, the only parts of an undo-supporting-application that anyone has cared to talk about on the web so far. So we'd better start looking at some of the harder parts now. In this episode: exception safety. Wed, 19 Jan 2011 00:00:01 GMT