Blog Archive

June 2009 C++ Standards Committee Mailing - New Working Draft and Concurrency Papers

Wednesday, 24 June 2009

The June 2009 mailing for the C++ Standards Committee was published today. This is the pre-meeting mailing for the upcoming committee meeting. Not only does it include the current C++0x working draft, but there are 39 other papers, of which 6 are concurrency related.

Concurrency-related papers

N2880: C++ object lifetime interactions with the threads API

This is a repeat of the same paper from the May 2009 mailing. It is referenced by several of the other concurrency papers.

N2888: Moving Futures - Proposed Wording for UK comments 335, 336, 337 and 338

This is the first of my papers in this mailing. The current working draft restricts std::unique_future to be MoveConstructible, but not MoveAssignable. It also restricts std::shared_future in a similar way, by making it CopyConstructible, but not CopyAssignable. This severely limits the potential use of such futures, so the UK panel filed comments on CD1 such as UK comment 335 which requested relaxation of these unnecessary restrictions. This paper to provide a detailed rationale for these changes, along with proposed wording.

N2889: An Asynchronous Call for C++

This is the first of two papers in the mailing that proposes a std::async() function for starting a task possibly asynchronously and returning a future for the result from that task. This addresses a need identified by UK comment 329 on CD1 for a simple way of starting a task with a return value asynchronously.

N2901: A simple async()

This is the second of the papers in the mailing that proposes a std::async() function for starting a task possibly asynchronously and returning a future for the result from that task.

The primary difference between the papers is the type of the returned future. N2889 proposes a new type of future (joining_future), whereas N2901 proposes using std::unique_future. There are also a few semantic differences surrounding whether tasks that run asynchronously aways do so on a new thread, or whether they may run on a thread that is reused for multiple tasks. Both papers provide a means for the caller to specify synchronous execution of tasks, or to allow the implementation to decide between synchronous execution and asynchronous execution on a case-by-case basis. N2901 also explicitly relies on the use of lambda functions or std::bind to bind parameters to a call, whereas N2889 supports specifying function arguments as additional parameters, as per the std::thread constructor (see my introduction to starting threads with arguments in C++0x).

Personally, I prefer the use of std::unique_future proposed in N2901, but I rather like the argument-passing semantics of N2889. I also think that the thread_local issues can be addressed by my proposal for that (N2907, see below). A final concern that I have is that calling the task inside future::get() can yield surprising behaviour, as futures can be passed across threads, so this may end up being called on another thread altogether. For synchronous execution, I would prefer invoking the task inside the std::async call itself, but delaying it to the get() does allow for work-stealing thread pools.

N2907: Managing the lifetime of thread_local variables with contexts

This is the second of my papers in this mailing. It proposes a potential solution to the lifetime-of-thread_local-variables issues from N2880 discussed in last month's blog post.

The idea is that you manage the lifetime of thread_local variables by constructing an instance of a new class std::thread_local_context. When the std::thread_local_context instance is destroyed, all thread_local variables created in that context are also destroyed. You can then construct a subsequent instance of std::thread_local_context, and create new thread_local instances in that new context. This means that you can reuse a thread for multiple unrelated tasks, without "spilling" thread_local variables from an earlier task into later tasks. It can also be used with a std::async() function to ensure that the thread_local variables are destroyed before the associated future is made ready.

N2917: N2880 Distilled, and a New Issue With Function Statics

This is Herb Sutter's take on the issues from N2880. He starts with a general discussion of the issue with detached threads and static destruction of globals, and then continues with a discussion of the issues surrounding the destruction of function-scoped thread_local variables. In particular, Herb focuses on something he calls Function thread_local statics poisoning thread_local destructors — if the destructor of a thread_local object x calls a function that itself uses a function-scope thread_local y, then the destructor of y might already have been called, resulting in undefined behaviour.

I found Herb's coverage of the issues surrounding detached threads dismissive of the idea that people could correctly write manual synchronization (e.g. using a std::condition_variable or a std::unique_future), even though this is common practice amongst those using POSIX threads (for example, in David Butenhof's Programming with POSIX Threads, he says "pthread_join is a convenience, not a rule", and describes examples using detached threads and condition variables to signal when the thread is done). I can see many possibilities for such usage, so as a consequence, I am personally in favour of his "solution" 1D: leave things as they are with regard to detached threads — it is already undefined behaviour to access something after its destruction.

However, the issue Herb raises with regard to order of destruction for thread_local variables is important, and not something that my std::thread_local_context proposal addresses. As Herb points out, the problem does exist with regard to function-local static variables already — thread_local just amplifies the problem. I am inclined to go with what POSIX threads does, and what boost::thread_specific_ptr does: make them "phoenix" variables that are re-initialized when accessed after destruction, and are thus added back onto the destructor list. This is Herb's solution 2B.

Other papers

Now that CD1 is out, and the committee is trying to get things pinned down for CD2, Concepts are getting a lot of discussion. There are therefore several papers on Concepts in the mailing. There are also papers on automatically defining move constructors, revised wording for lambdas, a proposal for unifying the function syntax, and several others. Check out the full list of papers for details.

Your comments

Do you have any comments on the papers (especially the concurrency ones, but if you have any comments on the others I'd like to know too)? Which std::async proposal do you prefer, or do you like aspects of both or neither? Do you think that thread_local_context objects combined with resurrecting thread_local objects on post-destruction access solves the thread_local issues?

Let me know by posting a comment.

Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

Importing an Existing Windows XP Installation into VirtualBox

Wednesday, 03 June 2009

On Monday morning one of the laptops I use for developing software died. Not a complete "nothing happens when I turn it on" kind of death — it still runs the POST checks OK — but it won't rebooted of its own accord whilst compiling some code and now no longer boots into Windows (no boot device, apparently). Now, I really didn't fancy having to install everything from scratch, and I've become quite a big fan of VirtualBox recently, so I thought I'd import it into VirtualBox. How hard could it be? The answer, I discovered, was "quite hard".

Since it seems that several other people have tried to import an existing Windows XP installation into VirtualBox and had problems doing so, I thought I'd document what I did for the benefits of anyone who is foolish enough to try this in the future.

Step 1: Clone the Disk into VirtualBox

The first thing to do is clone the disk into VirtualBox. I have a handy laptop disk caddy lying around in my office which enables you to convert a laptop hard disk into an external USB drive, so I took the disk out of the laptop and put it in that. I connected the drive to my linux box, and mounted the partition. A quick look round seemed to indicate that the partition was in working order and the data intact. So far so good. I unmounted the partition again, in preparation for cloning the disk.

I started VirtualBox and created a new virtual machine with a virtual disk the same size as the physical disk. I then booted the VM with the System Rescue CD that I use for partitioning and disk backups. You might prefer to use another disk cloning tool.

Once the VM was up and running, I connected the USB drive to the VM using VirtualBox's USB support and cloned the physical disk onto the virtual one. This took a long time, considering it was only a 30Gb disk. Someone will probably tell me that there are quicker ways of doing this, but it worked, and I hope I don't have to do it again.

Step 2: Try (and fail) to boot Windows

Once the clone was complete, I disconnected the USB drive and unmapped the System Rescue CD and rebooted the VM. Windows started to boot, but would hang on the splash screen. If you're trying this and Windows now boots in your VM, be very glad.

Booting into safe mode showed that the hang occurred after loading "mup.sys". It seems lots of people have had this problem, and mup.sys is not the problem — the problem is that the hardware drivers configured for the existing Windows installation don't match the VirtualBox emulated hardware in some drastic fashion. This is not surprising if you think about it. Anyway, like I said, lots of people have had this problem, and there are lots of suggested ways of fixing it, like booting with the Windows Recovery Console and adjusting which drivers are loaded, using the "repair" version of the registry and so forth. I tried most of them, and none worked. However, there was one suggestion that seemed worth following through, and it was a variant of this that I finally got working.

Step 3: Install Windows into a new VM

The suggestion that I finally got working was to install Windows on a new VM and swipe the SYSTEM registry hive from there. This registry hive contains all the information about your hardware that Windows needs to boot, so if you can get Windows booting in a VM then you can use the corresponding SYSTEM registry hive to boot the recovered installation. At least that's the theory; in practice it needs a bit of hackery to make it work.

Anyway, I installed Windows into the new VM, closed it down rebooted it with the System Rescue CD to retrieve the SYSTEM registry hive: C:\Windows\System32\config\SYSTEM. You cannot access this file when the system is running. I then booted my original VM with the System Rescue CD and copied the registry hive over, making sure I had a backup of the original. If you're doing this yourself don't change the hive on your original VM yet.

The system now booted into Windows. Well, almost — it booted up, but then displayed an LSASS message about being unable to update the password and rebooted. This cycle repeats ad infinitum, even in Safe Mode. So far not so good.

Step 4: Patching the SYSKEY

In practice, Windows installations have what's called a SYSKEY in order to prevent unauthorized people logging on to the system. This is a checksum of some variety which is spread across the SAM registry hive (which contains the user details), the SYSTEM hive and the SECURITY hive. If the SYSKEY is wrong, the system will boot up, but then display the message I was getting about LSASS being unable to update the password and reboot. In theory, you should be able to update all three registry hives together, but then all your user accounts get replaced, and I didn't fancy trying to get everything set up right again. This is where the hackery comes in, and where I am thankful to two people: firstly Clark from http://www.beginningtoseethelight.org/ who wrote an informative article on the Windows Security Accounts Manager which explains how the SYSKEY is stored in the registry hives, and secondly Petter Nordahl-Hagen who provides a boot disk for offline Windows password and registry editing.

According to the article on the Windows Security Manager, the portion of the SYSKEY store in the SYSTEM hive is stored as class key values on a few registry keys. Class key values are hidden from normal registry accesses, but Petter Nordahl-Hagen's registry editor can show them to you. So, I restored the original SYSTEM hive (I was glad I made a backup) and booted the VM from Petter's boot disk and looked at the class key values on the ControlSet001\Control\Lsa\Data, ControlSet001\Control\Lsa\GBG, ControlSet001\Control\Lsa\JD and ControlSet001\Control\Lsa\Skew1 keys from the SYSTEM hive. I noted these down for later. The values are all 16 bytes long: the ASCII values for 8 hex digits with null bytes between.

This is where the hackery comes in — I loaded the new SYSTEM hive (from the working Windows VM) into a hex editor and searched for the GBG key. The text should appear in a few places — one for the subkey of ControlSet001, one for the subkey of ControlSet002, and so forth. A few bytes after one of the occurrences you should see a sequence of 16 bytes that looks similar to the codes you wrote down: ASCII values for hex digits separated by spaces. Make a note of the original sequence and replace it with the GBG class key value from the working VM. Do the same for the Data, JD and Skew1 values. Near the Data values you should also see the same hex digit sequence without the separating null bytes. Replace that too. Now look at the values in the file near to where the registry key names occur to see if there are any other occurrences of the original hex digit sequences and replace these with the new values as well.

Save the patched SYSTEM registry hive and copy it into the VM being recovered.

Now for the moment of truth: boot the VM. If you've patched all the values correctly then it will boot into Windows. If not, then you'll get the LSASS message again. In this case, try booting into the "Last Known Good Configuration". This might work if you missed one of the occurrences of the original values. If it still doesn't work, load the hive back into your hex editor and have another go.

Step 5: Activate Windows and Install VirtualBox Guest Additions

Once Windows has booted successfully, it will update the SYSKEY entries across the remaining ControlSetXXX entries, so you don't need to worry if you missed some values. You'll need to re-activate Windows XP due to the huge change in hardware, but this should be relatively painless — if you enable a network adapter in the VM configuration then Windows can access the internet through your host's connection seamlessly. Once that's done you can proceed with install the VirtualBox guest additions to make it easier to work with the VM — mouse pointer integration, sensible screen resolutions, shared folders and so forth.

Was it quicker than installing everything from scratch? Possibly: I had a lot of software installed. It was certainly a lot more touch-and-go, and it was a bit scary patching the registry hive in a hex editor. It was quite fun though, and it felt good to get it working.

Posted by Anthony Williams
[/ general /] permanent link
Tags:
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

May 2009 C++ Standards Committee Mailing - Object Lifetimes and Threads

Monday, 18 May 2009

The May 2009 mailing for the C++ Standards Committee was published a couple of weeks ago. This is a minimal mailing between meetings, and only has a small number of papers.

The primary reason I'm mentioning it is because one of the papers is concurrency related: N2880: C++ object lifetime interactions with the threads API by Hans-J. Boehm and Lawrence Crowl. Hans and Lawrence are concerned about the implications of thread_local objects with destructors, and how you can safely clean up threads if you don't call join(). The issue arose during discussion of the proposed async() function, but is generally applicable.

thread_local variables and detached threads

Suppose you run a function on a thread for which you want the return value. You might be tempted to use std::packaged_task<> and std::unique_future<> for this; after all it's almost exactly what they're designed for:

#include <thread>
#include <future>
#include <iostream>

int find_the_answer_to_LtUaE();

std::unique_future<int> start_deep_thought()
{
    std::packaged_task<int()> task(find_the_answer_to_LtUaE);
    std::unique_future<int> future=task.get_future();
    std::thread t(std::move(task));
    t.detach();
    return future;
}

int main()
{
    std::unique_future<int> the_answer=start_deep_thought();
    do_stuff();
    std::cout<<"The answer="<<the_answer.get()<<std::endl;
}

The call to get() will wait for the task to finish, but not the thread. If there are no thread_local variable this is not a problem — the thread is detached so the library will clean up the resources assigned to it automatically. If there are thread_local variables (used in find_the_answer_to_LtUaE() for example), then this does cause a problem, because their destructors are not guaranteed to complete when get() returns. Consequently, the program may exit before the destructors of the thread_local variables have completed, and we have a race condition.

This race condition is particularly problematic if the thread accesses any objects of static storage duration, such as global variables. The program is exiting, so these are being destroyed; if the thread_local destructors in the still-running thread access global variables that have already been destroyed then your program has undefined behaviour.

This isn't the only problem that Hans and Lawrence discuss — they also discuss problems with thread_local and threads that are reused for multiple tasks — but I think it's the most important issue.

Solutions?

None of the solutions proposed in the paper are ideal. I particularly dislike the proposed removal of the detach() member function from std::thread. If you can't detach a thread directly then it makes functions like start_deep_thought() much harder to write, and people will find ways to simulate detached threads another way. Of the options presented, my preferred choice is to allow registration of a thread termination handler which is run after all thread_local objects have been destroyed. This handler can then be used to set the value on a future or notify a condition variable. However, it would make start_deep_thought() more complicated, as std::packaged_task<> wouldn't automatically make use of this mechanism unless it was extended to do so — if it did this every time then it would make it unusable in other contexts.

If anyone has any suggestions on how to handle the issue, please leave them in the comments below and I'll pass them on to the rest of the committee.

Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

"Introduction to Variadic Templates in C++0x" Article Online

Thursday, 07 May 2009

My latest article, Introduction to Variadic Templates in C++0x has been published at devx.com.

This article introduces the syntax for declaring and using variadic templates, along with some simple examples of variadic function templates and variadic class templates.

Posted by Anthony Williams
[/ news /] permanent link
Tags: , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

Designing Multithreaded Applications with C++0x: ACCU 2009 Slides

Tuesday, 28 April 2009

The ACCU 2009 conference has now finished, and life is getting back to normal. My presentation on "Designing Multithreaded Programs with C++0x" was well attended and I had a few people come up to me afterwards to say they enjoyed it, which is always nice.

Anyway, the purpose of this post is to say that the slides are now up. I've also posted the sample code for the Concurrent Queue and Numerical Integration demonstrations that I did using our just::thread implementation of the C++0x thread library.

Posted by Anthony Williams
[/ news /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

just::thread discount for ACCU 2009

Monday, 20 April 2009

As I mentioned back in January, I will be speaking on "Designing Multithreaded Applications with C++0x" at ACCU 2009 on Thursday.

To coincide with my presentation, our C++0x thread library, just::thread is available at a 25% discount until the 4th May 2009. just::thread provides implementations of the C++0x thread library facilities such as std::thread, std::mutex, std::unique_future<> and std::atomic<>. The current release works with Microsoft Visual Studio 2008, and gcc/linux support will be available soon — it is currently undergoing alpha testing.

Posted by Anthony Williams
[/ news /] permanent link
Tags: , , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

Multithreading in C++0x part 4: Protecting Shared Data

Saturday, 04 April 2009

This is the fourth of a series of blog posts introducing the new C++0x thread library. The first three parts covered starting threads in C++0x with simple functions, starting threads with function objects and additional arguments, and starting threads with member functions and reference arguments.

If you've read the previous parts of the series then you should be comfortable with starting threads to perform tasks "in the background", and waiting for them to finish. You can accomplish a lot of useful work like this, passing in the data to be accessed as parameters to the thread function, and then retrieving the result when the thread has completed. However, this won't do if you need to communicate between the threads whilst they are running — accessing shared memory concurrently from multiple threads causes undefined behaviour if either thread modifies the data. What you need here is some way of ensuring that the accesses are mutually exlusive, so only one thread can access the shared data at a time.

Mutual Exclusion with std::mutex

Mutexes are conceptually simple. A mutex is either "locked" or "unlocked", and threads try and lock the mutex when they wish to access some protected data. If the mutex is already locked then any other threads that try and lock the mutex will have to wait. Once the thread is done with the protected data it unlocks the mutex, and another thread can lock the mutex. If you make sure that threads always lock a particular mutex before accessing a particular piece of shared data then other threads are excluded from accessing the data until as long as another thread has locked the mutex. This prevents concurrent access from multiple threads, and avoids the undefined behaviour of data races. The simplest mutex provided by C++0x is std::mutex.

Now, whilst std::mutex has member functions for explicitly locking and unlocking, by far the most common use case in C++ is where the mutex needs to be locked for a specific region of code. This is where the std::lock_guard<> template comes in handy by providing for exactly this scenario. The constructor locks the mutex, and the destructor unlocks the mutex, so to lock a mutex for the duration of a block of code, just construct a std::lock_guard<> object as a local variable at the start of the block. For example, to protect a shared counter you can use std::lock_guard<> to ensure that the mutex is locked for either an increment or a query operation, as in the following example:

std::mutex m;
unsigned counter=0;

unsigned increment()
{
    std::lock_guard<std::mutex> lk(m);
    return ++counter;
}
unsigned query()
{
    std::lock_guard<std::mutex> lk(m);
    return counter;
}

This ensures that access to counter is serialized — if more than one thread calls query() concurrently then all but one will block until the first has exited the function, and the remaining threads will then have to take turns. Likewise, if more than one thread calls increment() concurrently then all but one will block. Since both functions lock the same mutex, if one thread calls query() and another calls increment() at the same time then one or other will have to block. This mutual exclusion is the whole point of a mutex.

Exception Safety and Mutexes

Using std::lock_guard<> to lock the mutex has additional benefits over manually locking and unlocking when it comes to exception safety. With manual locking, you have to ensure that the mutex is unlocked correctly on every exit path from the region where you need the mutex locked, including when the region exits due to an exception. Suppose for a moment that instead of protecting access to a simple integer counter we were protecting access to a std::string, and appending parts on the end. Appending to a string might have to allocate memory, and thus might throw an exception if the memory cannot be allocated. With std::lock_guard<> this still isn't a problem — if an exception is thrown, the mutex is still unlocked. To get the same behaviour with manual locking we have to use a catch block, as shown below:

std::mutex m;
std::string s;

void append_with_lock_guard(std::string const& extra)
{
    std::lock_guard<std::mutex> lk(m);
    s+=extra;
}

void append_with_manual_lock(std::string const& extra)
{
    m.lock();
    try
    {
        s+=extra;
        m.unlock();
    }
    catch(...)
    {
        m.unlock();
        throw;
    }
}

If you had to do this for every function which might throw an exception it would quickly get unwieldy. Of course, you still need to ensure that the code is exception-safe in general — it's no use automatically unlocking the mutex if the protected data is left in a state of disarray.

Next time

Next time we'll take a look at the std::unique_lock<> template, which provides more options than std::lock_guard<>.

Subscribe to the RSS feed RSS feed for this blog to be sure you don't miss the rest of the series.

Multithreading in C++0x Series

Here are the posts in this series so far:

Posted by Anthony Williams
[/ threading /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

March 2009 C++ Standards Committee Mailing - New C++0x Working Paper, Concurrency Changes

Monday, 30 March 2009

The March 2009 mailing for the C++ Standards Committee was published last week. This mailing contains the results of the first round of National Body voting on the C++0x draft, as well as the latest version of the C++0x working draft. This latest draft includes some changes in response to these NB comments, as agreed at the committee meeting at the beginning of March. Some of the changes related to concurrency and the thread library are listed below. The state of all comments (accepted, rejected, or unprocessed) can be found in N2863: C++ CD1 comment status.

The committee is intending to address all the comments (which may include rejecting some, as has already happened) in time to publish a second draft for National Body comments by the end of the year. If there is sufficient consensus on that draft, it will become the C++0x standard, otherwise it will have to undergo another round of revisions.

Concurrency-related Changes

The atomics library has only seen one accepted change so far, and that's a result of US issue 91: a failed compare_exchange operation is only atomic load rather than a read-modify-write operation. This should not have any impact on code that uses atomics, but can enable the implementation to be optimized on some architectures. The details can be seen in LWG issue 1043.

On the other hand, the thread library has seen a couple of accepted changes which will have user-visible consequences. These are:

std::thread destructor calls std::terminate() instead of detach()
Hans Boehm's paper N2082: A plea to reconsider detach-on-destruction for thread objects, was reviewed as part of US issue 97. The result is that if you do not explicitly call join() or detach() on your std::thread objects before they are destroyed then the library will call std::terminate(). This is to ensure that there are no unintentional "dangling threads" with references to local variables.
std::thread and std::unique_lock no longer have swap() functions that operate on rvalues
This change is in response to US issue 46, and the associated paper N2844: Fixing a Safety Problem with Rvalue References: Proposed Wording (Revision 1), which changes the way the rvalue-references work. In particular, an rvalue-reference no longer binds to an lvalue. Combined with the previous change to disallow destroying std::thread objects with an associated thread of execution this makes perfect sense: swapping two rvalue std::thread objects serves no purpose anyway, and swapping a std::thread variable with an rvalue would now call std::terminate() when the rvalue is destroyed at the end of the expression, if the variable had an associated thread of execution.
The single-argument std::thread constructor has been removed
This was UK issue 323. The variadic std::thread constructor provides all the necessary functionality.

There are also a few minor concurrency-related changes that have been approved, mostly along the lines of clarifying the text. There are a few more which are still under discussion, one of which is quite significant: UK issue 329. This comment proposes the addition of a new function std::async() which will execute a function asynchronously and return a std::unique_future which can be used to obtain the result. Details can be seen under LWG issue 1043.

Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

The Software Craftsmanship Manifesto

Wednesday, 11 March 2009

Do you care about the quality of your work as a software developer? Do you strive to produce the best software you can for your clients or employer? I don't mean basic level "does it work?" kind of quality — I hope we all aim to produce code that works. Does it matter to you if the code is well-crafted? Do you strive to write elegant software? Do you actively work to improve your skills as a developer?

There's been a lot of discussion about software quality on the internet recently. Uncle Bob, Joel Spolsky and Jeff Atwood got involved in the "Quality doesn't matter" debate, culminating in Uncle Bob talking on Jeff and Joel's Stack Overflow Podcast. James Bach even went as far as to hypothesise that Quality is Dead.

James has a point: in many instances it seems that people are quite happy to tolerate buggy software that's "good enough", and that developers are quite happy to ship such software. We're not perfect, and we will write code with bugs in, but to a large extent it's the attitude that counts. Whilst I accept that there may well be bugs in my code, I strive to avoid them, work hard to fix any that are found, and try and learn ways of reducing their occurrence in future. I also feel that software should be well-crafted so that it doesn't just work now, but will continue to work as it evolves, and such evolution should be as easy as possible. Of course, there's more to software quality than that — quality is Value to Some Person, and your job as a software developer is to ensure that your clients, customers or employers get the things that they value from the software you develop.

If this is something you feel strongly about, rest assured that you're not alone — there are many others who feel that Quality is Alive, to the extent that a few developers have got together to draft a Manifesto for Software Craftsmanship. The manifesto has over 1500 signatures (including mine) — why not add yours?

Posted by Anthony Williams
[/ design /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

Multithreading in C++0x part 3: Starting Threads with Member Functions and Reference Arguments

Thursday, 26 February 2009

This is the third of a series of blog posts introducing the new C++0x thread library. The first two parts covered Starting Threads in C++0x with simple functions, and starting threads with function objects and additional arguments.

If you've read the previous parts of the series then you've seen how to start threads with functions and function objects, with and without additional arguments. However, the function objects and arguments are always copied into the thread's internal storage. What if you wish to run a member function other than the function call operator, or pass a reference to an existing object?

The C++0x library can handle both these cases: the use of member functions with std::thread requires an additional argument for the object on which to invoke the member function, and references are handled with std::ref. Let's take a look at some examples.

Invoking a member function on a new thread

Starting a new thread which runs a member function of an existing object: you just pass a pointer to the member function and a value to use as the this pointer for the object in to the std::thread constructor.

#include <thread>
#include <iostream>

class SayHello
{
public:
    void greeting() const
    {
        std::cout<<"hello"<<std::endl;
    }
};

int main()
{
    SayHello x;
    std::thread t(&SayHello::greeting,&x);
    t.join();
}

You can of course pass additional arguments to the member function too:

#include <thread>
#include <iostream>

class SayHello
{
public:
    void greeting(std::string const& message) const
    {
        std::cout<<message<<std::endl;
    }
};

int main()
{
    SayHello x;
    std::thread t(&SayHello::greeting,&x,"goodbye");
    t.join();
}

Now, the preceding examples both a plain pointer to a local object for the this argument; if you're going to do that, you need to ensure that the object outlives the thread, otherwise there will be trouble. An alternative is to use a heap-allocated object and a reference-counted pointer such as std::shared_ptr<SayHello> to ensure that the object stays around as long as the thread does:

#include <>

int main()
{
    std::shared_ptr<SayHello> p(new SayHello);
    std::thread t(&SayHello::greeting,p,"goodbye");
    t.join();
}

So far, everything we've looked at has involved copying the arguments and thread functions into the internal storage of a thread even if those arguments are pointers, as in the this pointers for the member functions. What if you want to pass in a reference to an existing object, and a pointer just won't do? That is the task of std::ref.

Passing function objects and arguments to a thread by reference

Suppose you have an object that implements the function call operator, and you wish to invoke it on a new thread. The thing is you want to invoke the function call operator on this particular object rather than copying it. You could use the member function support to call operator() explicitly, but that seems a bit of a mess given that it is callable already. This is the first instance in which std::ref can help — if x is a callable object, then std::ref(x) is too, so we can pass std::ref(x) as our function when we start the thread, as below:

#include <thread>
#include <iostream>
#include <functional> // for std::ref

class PrintThis
{
public:
    void operator()() const
    {
        std::cout<<"this="<<this<<std::endl;
    }
};

int main()
{
    PrintThis x;
    x();
    std::thread t(std::ref(x));
    t.join();
    std::thread t2(x);
    t2.join();
}

In this case, the function call operator just prints the address of the object. The exact form and values of the output will vary, but the principle is the same: this little program should output three lines. The first two should be the same, whilst the third is different, as it invokes the function call operator on a copy of x. For one run on my system it printed the following:

this=0x7fffb08bf7ef
this=0x7fffb08bf7ef
this=0x42674098

Of course, std::ref can be used for other arguments too — the following code will print "x=43":

#include <thread>
#include <iostream>
#include <functional>

void increment(int& i)
{
    ++i;
}

int main()
{
    int x=42;
    std::thread t(increment,std::ref(x));
    t.join();
    std::cout<<"x="<<x<<std::endl;
}

When passing in references like this (or pointers for that matter), you need to be careful not only that the referenced object outlives the thread, but also that appropriate synchronization is used. In this case it is fine, because we only access x before we start the thread and after it is done, but concurrent access would need protection with a mutex.

Next time

That wraps up all the variations on starting threads; next time we'll look at using mutexes to protect data from concurrent modification.

Subscribe to the RSS feed RSS feed for this blog to be sure you don't miss the rest of the series.

Multithreading in C++0x Series

Here are the posts in this series so far:

Posted by Anthony Williams
[/ threading /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter?

Older entries