Blog Archive
CppCast Interview
Wednesday, 07 October 2015
I was pleasantly surprised when Rob and Jason from CppCast approached me to be a guest on their podcast, to talk about concurrency in C++11 and C++14. The recording went live last week.
We had a brief discussion about the C++ Core Guidelines introduced by Bjarne Stroustrup and Herb Sutter at this year's CppCon, and the Guideline Support Library (GSL) that accompanies it, before moving on to the concurrency discussion.
As well as the C++11 and C++14 threading facilities, I also talked about the Parallelism TS, which has been officially published, and the Concurrency TS, which is still being worked on.
I always enjoy talking about concurrency, and this was no exception. I hope you enjoy listening.
Posted by Anthony Williams
[/ news /] permanent link
Tags: cppcast, interview, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
just::thread C++11 and C++14 Thread Library V2.2 released
Wednesday, 30 September 2015
I am pleased to announce that version 2.2 of
just::thread, our C++11 and C++14 Thread Library
has just been released with full support for the latest draft of the Concurrency
TS, and support for Microsoft Visual Studio 2015.
New features
New facilities from the Concurrency TS:
- A lock-free implementation of
atomic_shared_ptrandatomic_weak_ptr— see my earlier blog post onatomic_shared_ptr - Latches — signal waiting threads once a specified number of count-down events have occurred.
- Barriers — block a group of threads until they are all ready to proceed.
future::then()— schedule a task to run when a future becomes ready.when_any()— create a future that is ready when any of a set of futures is ready.when_all()— create a future that is ready when all of a set of futures are ready.
Also:
jss::joining_thread— a simple wrapper aroundstd::threadthat always joins in its destructor.
Supported compilers
Just::Thread is now supported for the following compilers:
- Microsoft Windows XP and later:
- Microsoft Visual Studio 2005, 2008, 2010, 2012, 2013 and 2015
- TDM gcc 4.5.2, 4.6.1 and 4.8.1
- Debian and Ubuntu linux (Ubuntu Jaunty and later)
- g++ 4.3, 4.4, 4.5, 4.6, 4.7, 4.8 and 4.9
- Fedora linux
- Fedora 13: g++ 4.4
- Fedora 14: g++ 4.5
- Fedora 15: g++ 4.6
- Fedora 16: g++ 4.6
- Fedora 17: g++ 4.7.2 or later
- Fedora 18: g++ 4.7.2 or later
- Fedora 19: g++ 4.8
- Fedora 20: g++ 4.8
- Fedora 21: g++ 4.9
- Intel x86 MacOSX Snow Leopard or later
- MacPorts g++ 4.3, 4.4, 4.5, 4.6, 4.7 and 4.8
Get your copy of Just::Thread
Purchase your copy and get started with the C++11 and C++14 thread library now.
Posted by Anthony Williams
[/ news /] permanent link
Tags: multithreading, concurrency, C++0x, C++11, C++14
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Core C++ - Destructors and RAII
Thursday, 24 September 2015
Though I love many features of C++, the feature that I think is probably the most important for writing robust code is deterministic destruction and destructors.
The destructor for an object is called when that object is destroyed, whether explicitly with the delete operator, or implicitly when it goes out of scope. This provides an opportunity to clean up any resources held by that object, thus making it easy to avoid leaking memory, or indeed any kind of resource.
This has led to the idiom commonly known as Resource Acquisition Is Initialization (RAII) — a class acquires some resource when it is initialised (in its constructor), and then releases it in its destructor. A better acronym would be DIRR — Destruction Is Resource Release — as the release in the destructor is the important part, but RAII is what has stuck.
The power of RAII
This is incredibly powerful, and makes it so much easier to write robust
code. It doesn't matter how the object goes out of scope, whether it is due to
just reaching the end of the block, or due to a control transfer statement such
as goto, break or continue, or because the function has returned, or
because an exception is thrown. However the object is destroyed, the destructor
is run.
This means you don't have to litter your code with calls to cleanup functions. You just write a class to manage a resource and have the destructor call the cleanup function. Then you can just create objects of that type and know that the resource will be correctly cleaned up when the object is destroyed.
No more leaks
If you don't use resource management classes, it can be hard to ensure that your resources are correctly released on all code paths, especially in the presence of exceptions. Even without exceptions, it's easy to fail to release a resource on a rarely-executed code path. How many programs have you seen with memory leaks?
Writing a resource management class for a particular resource is really easy,
and there are many already written for you. The C++ standard is full of
them. There are the obvious ones like std::unique_ptr and std::shared_ptr
for managing heap-allocated objects, and std::lock_guard for managing lock
ownership, but also std::fstream and std::file_buf for managing file
handles, and of course all the container types.
I like to use std::vector<char> as a generic buffer-management class for
handling buffers for legacy C-style APIs. The always-contiguous guarantee means
that it's great for anything that needs a char buffer, and there is no messing
around with reallocor the potential for buffer overrun you get with fixed-size
buffers.
For example, many Windows API calls take a buffer in which they return the
result, as well as a length parameter to specify how big the buffer is. If the
buffer isn't big enough, they return the required buffer size. We can use this
with std::vector<char> to ensure that our buffer is big enough. For example,
the following code retrieves the full path name for a given relative path,
without requiring any knowledge about how much space is required beforehand:
std::string get_full_path_name(std::string const& relative_path){
DWORD const required_size=GetFullPathName(relative_path.c_str(),0,NULL,&filePart);
std::vector<char> buffer(required_size);
if(!GetFullPathName(relative_path.c_str(),buffer.size(),buffer.data(),&filePart))
throw std::runtime_error("Unable to retrieve full path name");
return std::string(buffer.data());
}
Nowhere do we need to explicitly free the buffer: the destructor takes care of that for us, whether we return successfully or throw. Writing resource management classes enables us to extend this to every type of resource: no more leaks!
Writing resource management classes
A basic resource management class needs just two things: a constructor that takes ownership of the resource, and a destructor that releases ownership. Unless you need to transfer ownership of your resource between scopes you will also want to prevent copying or moving of your class.
class my_resource_handle{
public:
my_resource_handle(...){
// acquire resource
}
~my_resource_handle(){
// release resource
}
my_resource_handle(my_resource_handle const&)=delete;
my_resource_handle& operator=(my_resource_handle const&)=delete;
};
Sometimes the resource ownership might be represented by some kind of token,
such as a file handle, whereas in other cases it might be more conceptual, like
a mutex lock. Whatever the case, you need to store enough data in your class to
ensure that you can release the resource in the destructor. Sometimes you might
want your class to take ownership of a resource acquired elsewhere. In this
case, you can provide a constructor to do that. std::lock_guard is a nice
example of a resource-ownership class that manages an ephemeral resource, and
can optionally take ownership of a resource acquired elsewhere. It just holds a
reference to the lockable object being locked and unlocked; the ownership of the
lock is implicit. The first constructor always acquires the lock itself, whereas
the second constructor taking an adopt_lock_t parameter allows it to take
ownership of a lock acquired elsewhere.
template<typename Lockable>
class lock_guard{
Lockable& lockable;
public:
explicit lock_guard(Lockable& lockable_):
lockable(lockable_){
lockable.lock();
}
explicit lock_guard(Lockable& lockable_,adopt_lock_t):
lockable(lockable_){}
~lock_guard(){
lockable.unlock();
}
lock_guard(lock_guard const&)=delete;
lock_guard& operator=(lock_guard const&)=delete;
};
Using std::lock_guard to manage your mutex locks means you no longer have to
worry about ensuring that your mutexes are unlocked when you exit a function:
this just happens automatically, which is not only easy to manage conceptually,
but less typing too.
Here is another simple example: a class that saves the state of a Windows GDI DC, such as the current pen, font and colours.
class dc_saver{
HDC dc;
int state;
public:
dc_saver(HDC dc_):
dc(dc_),state(SaveDC(dc)){
if(!state)
throw std::runtime_error("Unable to save DC state");
}
~dc_saver(){
RestoreDC(dc,state);
}
dc_saver(dc_saver const&)=delete;
dc_saver& operator=(dc_saver const&)=delete;
};
You could use this as part of some drawing to save the state of the DC before changing it for local use, such as setting a new font or new pen colour. This way, you know that whatever the state of the DC was when you started your function, it will be safely restored when you exit, even if you exit via an exception, or you have multiple return points in your code.
void draw_something(HDC dc){
dc_saver guard(dc);
// set pen, font etc.
// do drawing
} // DC properties are always restored here
As you can see from these examples, the resource being managed could be anything: a file handle, a database connection handle, a lock, a saved graphics state, anything.
Transfer season
Sometimes you want to transfer ownership of the resource between scopes. The classical use case for this is you have some kind of factory function that acquires the resource and then returns a handle to the caller. If you make your resource management class movable then you can still benefit from the guaranteed leak protection. Indeed, you can build it in at the source: if your factory returns an instance of your resource management rather than a raw handle then you are protected from the start. If you never expose the raw handle, but instead provide additional functions in the resource management class to interact with it, then you are guaranteed that your resource will not leak.
std::async provides us with a nice example of this in action. When you start a
task with std::async, then you get back a std::future object that references
the shared state. If your task is running asynchronously, then the destructor
for the future object will wait for the task to complete. You can, however, wait
explicitly beforehand, or return the std::future to the caller of your
function in order to transfer ownership of the "resource": the running
asynchronous task.
You can add such ownership-transfer facilities to your own resource management classes without much hassle, but you need to ensure that you don't end up with multiple objects thinking they own the same resource, or resources not being released due to mistakes in the transfer code. This is why we start with non-copyable and non-movable classes by deleting the copy operations: then you can't accidentally end up with botched ownership transfer, you have to write it explicitly, so you can ensure you get it right.
The key part is to ensure that not only does the new instance that is taking ownership of the resource hold the proper details to release it, but the old instance will no longer try and release the resource: double-frees can be just as bad as leaks.
std::unique_lock is the big brother of std::lock_guard that allows transfer
of ownership. It also has a bunch of additional member functions for acquiring
and releasing locks, but we're going to focus on just the move semantics. Note:
it is still not copyable: only one object can own a given lock, but we can
change which object that is.
template<typename Lockable>
class unique_lock{
Lockable* lockable;
public:
explicit unique_lock(Lockable& lockable_):
lockable(&lockable_){
lockable->lock();
}
explicit unique_lock(Lockable& lockable_,adopt_lock_t):
lockable(&lockable_){}
~unique_lock(){
if(lockable)
lockable->unlock();
}
unique_lock(unique_lock && other):
lockable(other.lockable){
other.lockable=nullptr;
}
unique_lock& operator=(unique_lock && other){
unique_lock temp(std::move(other));
std::swap(lockable,temp.lockable);
return *this;
}
unique_lock(unique_lock const&)=delete;
unique_lock& operator=(unique_lock const&)=delete;
};
Firstly, see how in order to allow the assignment, we have to hold a pointer to
the Lockable object rather than a reference, and in the destructor we have to
check whether or not the pointer is nullptr. Secondly, see that in the move
constructor we explicitly set the pointer to nullptrfor the source of our
move, so that the source will no longer try and release the lock in its
destructor.
Finally, look at the move-assignment operator. We have explicitly transferred
ownership from the source object into a new temporary object, and then swapped
the resources owned by the target object and our temporary. This ensures that
when the temporary goes out of scope, its destructor will release the lock
owned by our target beforehand, if there was one. This is a common pattern among
resource management classes that allow ownership transfer, as it keeps
everything tidy without having to explicitly write the resource cleanup code in
more than one place. If you've written a swap function for your class then you
might well use that here rather than directly exchanging the members, to avoid
duplication.
Wrapping up
Using resource management classes can simplify your code, and reduce the need for debugging, so use RAII for all your resources to avoid leaks and other resource management issues. There are many classes already provided in the C++ Standard Library or third-party libraries, but it is trivial to write your own resource management wrapper for any resource if there is a well-defined API for acquiring and releasing the resource.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: cplusplus, destructors, RAII
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Agile on the Beach Conference Report
Tuesday, 15 September 2015
The Agile On The Beach 2015 conference took place last week, on 3rd/4th September. It was hosted at the Performance Centre at the Tremough campus of Falmouth University and the University of Exeter, near Falmouth, Cornwall, UK.
The conference featured 48 sessions over the 2 days, with 5 tracks running on the Thursday and 4 tracks running on the Friday. Topics covered everything from estimating, project management, and implementing agile to source control, testing practices, and teaching software developers.
What follows is a summary of the sessions I attended. Slides and videos of all the talks should be available from the Agile On The Beach website in due course.
Farley's 3 laws
The opening keynote was Dave Farley, coauthor of Continuous Delivery. Rather than talk to us about continuous delivery, he introduced Farley's 3 laws:
- People are crap
- Stuff is more complicated than you think
- All stuff is interesting (if you look at it in the right way)
People are slow, lazy and unobservant. Thinking requires real effort, measurable in brain scans, so we are hard-wired to avoid it where possible, making snap judgements and guesses. Our eyes cannot take in a whole scene at once, so they scan around, and our brain fills in the areas we're not looking at for that millisecond with what it thinks is likely based on what was there when we last looked in that direction.
The best indicator for whether or not people will agree with you in a meeting is how good the food was: feed people well and they will look favourably on you and your suggestions.
Our brain is a pattern-recognition engine. If we can recognize a pattern then we don't need to consciously think about the details. This has some surprising consequences, such as that we can hear speech in a simple set of sine waves. Dave played us some audio files of sine waves, then someone talking, and then the sine waves again: we could all hear the speech in the second set of sine waves. He also showed us various optical illusions, with static images that appear to move, black and white images that appear in colour and so forth.
By being aware of our tendencies to be lazy, and jump to conclusions we can consciously decide to pay attention to how things are. Apply the scientific method: hypothesize, test, repeat. This is the core of Agile and Lean, and the manufacturing ideas of Dr W. Edwards Demming, and it's how we managed to get a man on the moon in 1969 despite barely any of the technology existing when President Kennedy suggested the idea.
- Don't do things because we've always done them that way,
- Don't start work on a guess or jump to conclusions,
- Don't be afraid of failure,
- Question everything,
- Always think "how can I test this?",
- Iterate to learn and adapt.
Remember: everything is interesting.
ClojureScript
After the break, Jim Barritt was presenting a live demo of ClojureScript. This is essentially just a Clojure-to-JavaScript compiler, which allows you to write Web applications in Clojure.
One particularly neat aspect is the way that it integrates with the server side code, so you can have Clojure code running both on the server and in the browser.
Another nice feature is that error messages in the browser console refer directly to the line in the ClojureScript file that the JavaScript was generated from, rather than a line in the generated JavaScript.
Test-driving User Interfaces
Next up was my presentation on Test-driving User Interfaces. The main thrust of my presentation is that in principle User Interfaces are no harder to test-drive than any other bit of code, we just need to know how.
Also, desktop frameworks don't tend to support testing UIs, so we need to develop our own library of support code to drive the UI from within our tests.
After my presentation it was time for lunch.
Only You can Analyze the Code
What happens if only one member of the team is allowed to run static analysis tools on a codebase? That is the question that Anna-Jayne Metcalfe's talk was there to answer after lunch.
As you might guess, the answer is not good. Though it can be nice to get a heads-up on the state of your code base, this is all you really get if only one person does it. To get the most out of static analysis tools you need to have the whole team involved, and have the analysis run before check-in.
On a large legacy code base you might well end up with several lint warnings per line for you crank up the analysis level too much. Wading through millions of messages to find the important ones is not for the faint-hearted. Better is to set the warning level to a minimum, so only the nastiest issues get flagged. If you run the analysis locally, before check-in, you have a chance to fix things before the code gets committed.
If you're going to do Scrum, do it right
That was the message of Amy Thompson's talk "Scrum ... Really?". This was more of a pep-talk selling the benefits of doing Scrum by the book than a "how-to", but there were titbits of real advice in there on things you should be doing:
- Scrum needs proper buy-in at all levels of management
- Have a physical progress board, so everyone can see the state of the project
- The Product Owner needs to work on the stories before adding them to the backlog to provide a clear definition of done
Don't let your organization do "Scrum, but ...".
Use contract tests to ease integration pain
The penultimate talk of the first day was Stefan Smith's talk titled "Escape the integration syrup with contract tests". If your software is part of an ecosystem of cooperating pieces of software then you need to ensure that everything works together. This is the role of integration tests.
However, if each piece of the ecosystem has its own release schedule then this can make integration difficult. Organizations typically wrap a combination of builds of the individual components into a single monolithic system build for integration testing, which then moves through the various test stages as a package.
If you're trying to release a small change to one of the components this can cause a big delay, as your change has to join the next release train.
Contract tests can help. Each component carries with it tests for the required behaviour of all the components it interacts with. These are packaged alongside the component, and come in two parts: a test client that mimics the behaviour of this component and the way it uses other components, and a dummy server that provides a minimal test-double that demonstrates the required behaviour.
When testing the component itself, you run it against the test-double. You also need to run the test-client against the test-double to ensure that you keep your behaviour in sync. When testing interactions between components you run the test-client from one against the real implementation of the other, and vice-versa.
Since these test-clients embody the interface to the component, they allow you to test whether components work together without having to do full integration tests. If component A is used by components B and C, when developing component A version 57, you can run it against the contract tests for all the versions of components B and C in the release pipeline. If all the contract tests pass, you may then be able to bring this new release forward to the pre-production staging area for final integration tests without having to go through the full pipeline.
Done right, this can save a lot of pain and allow faster deployment of individual components. However, this is not free. You have to pay attention to ensure the contract tests are properly updated, and there can be many combinations to run, which requires time and resources.
Mob rule
"Product Development in an Unruly Mob" was the title of the final talk I attended on the first day. Benji Weber and Alex Wilson from Unruly spoke about a practice they use called "Mob Programming". This is pair programming taken a step further, so the whole team sits in a "mob" around a single computer, rather than each person doing their own thing.
You need a large screen so everyone can see — they use a 50" TV — as well as a smaller screen for the person at the keyboard to use.
One important point is that the person at the keyboard should not do anything that has not been decided by the group as a whole. This makes it possible for non-programmers to drive. They also suggest that you need to change the driver frequently so everyone on the team gets a turn relatively often, and everyone feels involved.
They commented that the closest they've ever got to an "ideal programming day" was when mob programming.
They don't mob all the time; sometimes people will peel off the mob to take a break, or to work on something that really is a single-person task. However, they try to eliminate the need for such single-person tasks.
Their experience has shown that mob programming can help eliminate the common team dysfunctions: it builds trust, as you're all there together, it reduces conflict because everyone can get heard, and it builds commitment and accountability as the whole team is there and everything is decided together.
Party!!!
The first day ended with a party on the beach. This was a great opportunity to have discussions with people about the day's talks, as well as to discuss wider issues around software development and life.
Day 2
The second day of the conference was just as good as the first. I missed out on watching any of the sessions in one of the afternoon slots due to having extended discussions in the break, but that's the way things go — the discussions with other delegates are probably more valuable than the sessions themselves anyway.
Agile Leadership
The Friday morning keynote was by Jenni Jepsen, on "Agile Leadership and Teams".
Agile works because the processes support the reward mechanisms in the brain; the neuroscience proves that Agile works.
We work best when we have moderate levels of stress hormones. Too much stress and our brain shuts down and performance suffers. Likewise for too little, but that's not a common concern in the workplace. If you're over-stressed then support and encouragement can help reduce stress, and improve performance. The collaboration techniques in Agile methodologies have this effect.
Our brains are great at pattern matching, so we can manage to read sentences with all the letters in each word scrambled, provided the first and last letters of each word are correct.
If we have a feeling of control, our Pre-Frontal Cortex functions better, and can override the stress response from our limbic system.
If we're stressed for 2 weeks we can become more negative as our brain is rewired. We then need 2 weeks of no-stress to recover. By focusing on positive things then our brain is rewired in a positive fashion.
Agile processes help with providing us these positive things:
- Craftsmanship and pride in what we're doing
- Certainty, having an overview of what's coming next. Planning for uncertainty creates certainty in the brain: we're certain things are going to change
- Influence and autonomy: we plan the details ourselves in our teams, rather than having things imposed from above
- Connection with people, by working in teams
Focusing on relationships before tasks helps us get to the tasks quicker, and do the tasks better.
Taking Back BDD
Next up was Konstantin Kudryashov, with the first of the two talks I attended on Behaviour Driven Development (BDD).
One of the central aspects of BDD is the structure of the BDD tests: Given a setup, when I do something, then the outcome is this. Konstantin wants us to really drill down in these scenarios, and use them as a focus for a conversation with the customer. This can really help us build our ubiquitous language, and help with Domain Driven Design (DDD).
Konstantin used an example of an application to help conference delegates plan which talks they are going to attend. This was something we could all relate to, since the conference organisers were plugging the use of the free Whova app for doing exactly this.
"Given that there's a conference 'Agile on the Beach', and that the first session in track 1 on Friday is 'Taking Back BDD' ..."
Talk to the customer: what do we mean "there's a conference 'Agile on the Beach'"? What do we mean by "session"? What do we mean by "track 1"?
Each of these questions can help us flesh out our scenario, and help drive the interface of our domain objects. Create factory functions that mimic the structure of the sentence:
$conference=Conference::namedWithTracks("Agile on the Beach",5);
BDD drives the conversations that help us build the ubiquitous language for our DDD. This leads to fewer misunderstandings, as the customer, the programmer and the code all use the same terms for the same things, which leads to happier customers.
Watching Konstantin made me think "I really ought to do this on my projects".
10 things you need to know about BDD
The second BDD talk was in the very next slot. This one was presented by Seb Rose. He first provided 10 (base 12) things you need to know about BDD, which he reduced to 10 (base 2) things you need to know at the end.
Fundamentally, BDD is about collaboration and conversations between the developers, testers and customers. Tools like Cucumber and Specflow provide nice ways of automating the test scenarios that arise from the conversations, but you don't need them to make it work.
Code Club : Creating the next generation of software developers
After lunch, Mike Trebilcock spoke with enthusiasm about what we can do to encourage young people to get interested in software development.
Mike used the metaphor of a "pipeline" to anchor his talk, with key markers at the various stages of education from primary school onwards, culminating in a career in software development. This is a "leaky" pipeline: not everyone from every stage will continue to have an interest in software development at the next stage.
Mike wants us to work to cultivate interest in children at primary school, and then keep that interest all through education, to ensure we have a new generation of skilled software developers. He encouraged us to help with or start Code Clubs, and to work with schools and colleges on their curriculum to ensure that they are teaching the things we as an industry would find valuable.
Cornwall College and Falmouth University have new degree courses on game development and software development. The software development course in particular has been developed in association with Software Cornwall to provide the skills that would be useful for local software companies.
All of us can help teach and encourage the next generation of programmers.
Financial Prioritization
Antonello Nardini's presentation hinged on a single premise: if we can estimate the actual monetary business value and cost of our stories, then we can use that information to aid in prioritization, and thus help our customers get more money sooner, or maintain cashflow.
Sadly, there was nothing in this that wasn't covered in Mike Cohn's Agile Estimating and Planning. Also, I find the premise to be flawed: it is rare to be able to predict with any certainty what the monetary value of a feature is likely to be. Doing fancy calculations such as Internal Rate of Return on estimated values just compounds the uncertainty, and gives you numbers that look good, but are basically useless.
I tried asking Antonello how he dealt with this in practice, but didn't come away with anything I could use: "it depends". I won't be trying to use financial prioritization of my projects.
What is Agile?
Woody Zuill presented the conference Endnote. He started by talking to us about the Agile Manifesto: what does it mean? What does "over" mean in this context?
He likes to think of it like "I value being fit and healthy OVER eating junk food". It doesn't mean that eating junk food is ruled out per se, but you try not to do it, especially not to the point that it stops you being fit and healthy.
Woody reminded us of John Gall's writing: complex systems that work invariably have come from simple systems that work, so start there, don't go straight for a big complex system.
You might not even need the whole system that you first envisaged. Woody tells the story of a project he worked on where there were 12 calculations that the business wanted automating to improve their production. Doing all 12 would have been a big complex task, so Woody's team started with the one calculation that was most vital to automate. When this was done, working and released, they worked on the others one at a time. After the 4th was done, the business said "that's enough" — we don't need the others done after all, they're not that valuable. If they'd started doing a system for all 12 calculations then it would have been much more complex, much more expensive, and would have done a load of work that ultimately the customer didn't actually need.
Woody sums up this approach with "Deliver features until bored" — keep delivering features until the customer is bored, and doesn't want to invest any more in the product.
I'll be back
Agile on the Beach 2015 was a great conference, and I'll be back next year. The question is: will you? Mega early bird tickets for 2016 are already on sale.
Posted by Anthony Williams
[/ news /] permanent link
Tags: agile, agileotb, conference
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Slides for my Test Driving User Interfaces Presentation
Friday, 04 September 2015
I presented my talk on Test Driving User Interfaces at Agile On The Beach yesterday. It was reasonably well attended and there were some interesting questions from the audience.
Here are my slides in case you missed it, or just wanted to remind yourself of what they said.
Posted by Anthony Williams
[/ news /] permanent link
Tags: agilotb, tdd, ui
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Why do we need atomic_shared_ptr?
Friday, 21 August 2015
One of the new class templates provided in the upcoming
Concurrency TS
is
atomic_shared_ptr,
along with its counterpart atomic_weak_ptr. As you might guess, these are the
std::shared_ptr and std::weak_ptr equivalents of std::atomic<T*>, but why
would one need them? Doesn't std::shared_ptr already have to synchronize the
reference count?
std::shared_ptr and multiple threads
std::shared_ptr works great in multiple threads, provided each thread has its
own copy or copies. In this case, the changes to the reference count are indeed
synchronized, and everything just works, provided of course that what you do
with the shared data is correctly synchronized.
class MyClass;
void thread_func(std::shared_ptr<MyClass> sp){
sp->do_stuff();
std::shared_ptr<MyClass> sp2=sp;
do_stuff_with(sp2);
}
int main(){
std::shared_ptr<MyClass> sp(new MyClass);
std::thread thread1(thread_func,sp);
std::thread thread2(thread_func,sp);
thread2.join();
thread1.join();
}
In this example, you need to ensure that it is safe to call
MyClass::do_stuff() and do_stuff_with() from multiple threads concurrently
on the same instance, but the reference counts are handled OK.
The problems come when you try and share a single std::shared_ptr instance
between threads.
Sharing a std::shared_ptr instance between threads
I could provide a trivial example of a std::shared_ptr instance shared between
threads, but instead we'll look at something a little more interesting, to give
a better feel for why you might need it.
Consider for a moment a simple singly-linked list, where each node holds a pointer to the next:
class MyList{
struct Node{
MyClass data;
std::unique_ptr<Node> next;
};
std::unique_ptr<Node> head;
// constructors etc. omitted.
};
If we're going to access this from 2 threads, then we have a choice:
- We could wrap the whole object with a mutex, so only one thread is accessing the list at a time, or
- We could try and allow concurrent accesses.
For the sake of this article, we're going to assume we're allowing concurrent accesses.
Let's start simply: we want to traverse the list. Writing a traversal function is easy:
class MyList{
void traverse(std::function<void(MyClass)> f){
Node* p=head.get();
while(p){
f(p->data);
p=p->next;
}
};
Assuming the list is immutable, this is fine, but immutable lists are no fun! We want to remove items from the front of our list. What changes do we need to make to support that?
Removing from the front of the list
If everything was single threaded, removing an element would be easy:
class MyList{
void pop_front(){
Node* p=head.get();
if(p){
head=std::move(p->next);
}
}
};
If the list is not empty, the new head is the next pointer of the old head. However, we've got multiple threads accessing this list, so things aren't so straightforward.
Suppose we have a list of 3 elements.
A -> B -> C
If one thread is traversing the list, and another is removing the first element, there is a potential for a race.
- Thread X reads the
headpointer for the list and gets a pointer to A. - Thread Y removes A from the list and deletes it.
- Thread X tries to access the
datafor node A, but node A has been deleted, so we have a dangling pointer and undefined behaviour.
How can we fix it?
The first thing to change is to make all our std::unique_ptrs into
std::shared_ptrs, and have our traversal function take a std::shared_ptr
copy rather than using a raw pointer. That way, node A won't be deleted
immediately, since our traversing thread still holds a reference.
class MyList{
struct Node{
MyClass data;
std::shared_ptr<Node> next;
};
std::shared_ptr<Node> head;
void traverse(std::function<void(MyClass)> f){
std::shared_ptr<Node> p=head;
while(p){
f(p->data);
p=p->next;
}
}
void pop_front(){
std::shared_ptr<Node> p=head;
if(p){
head=std::move(p->next);
}
}
// constructors etc. omitted.
};
Unfortunately that only fixes that race condition. There is a second race that is just as bad.
The second race condition
The second race condition is on head itself. In order to traverse the list,
thread X has to read head. In the mean time, thread Y is updating head. This
is the very definition of a data race, and is thus undefined behaviour.
We therefore need to do something to fix it.
We could use a mutex to protect head. This would be more fine-grained than a
whole-list mutex, since it would only be held for the brief time when the
pointer was being read or changed. However, we don't need to: we can use
std::experimental::atomic_shared_ptr instead.
The implementation is allowed to use a mutex internally with
atomic_shared_ptr, in which case we haven't gained anything with respect to
performance or concurrency, but we have gained by reducing the maintenance
load on our code. We don't have to have an explicit mutex data member, and we
don't have to remember to lock it and unlock it correctly around every access to
head. Instead, we can defer all that to the implementation with a single line
change:
class MyList{
std::experimental::atomic_shared_ptr<Node> head;
};
Now, the read from head no longer races with a store to head: the
implementation of atomic_shared_ptr takes care of ensuring that the load gets
either the new value or the old one without problem, and ensuring that the
reference count is correctly updated.
Unfortunately, the code is still not bug free: what if 2 threads try and remove a node at the same time.
Race 3: double removal
As it stands, pop_front assumes it is the only modifying thread, which leaves
the door wide open for race conditions. If 2 threads call pop_front
concurrently, we can get the following scenario:
- Thread X loads
headand gets a pointer to node A. - Thread Y loads
headand gets a pointer to node A. - Thread X replaces
headwithA->next, which is node B. - Thread Y replaces
headwithA->next, which is node B.
So, two threads call pop_front, but only one node is removed. That's a bug.
The fix here is to use the ubiquitous compare_exchange_strong function, a staple
of any programmer who's ever written code that uses atomic variables.
class MyList{
void pop_front(){
std::shared_ptr<Node> p=head;
while(p &&
!head.compare_exchange_strong(p,p->next));
}
};
If head has changed since we loaded it, then the call to
compare_exchange_strong will return false, and reload p for us. We then
loop again, checking that p is still non-null.
This will ensure that two calls to pop_front removes two nodes (if there are 2
nodes) without problems either with each other, or with a traversing thread.
Experienced lock-free programmers might well be thinking "what about the ABA problem?" right about now. Thankfully, we don't have to worry!
What no ABA problem?
That's right, pop_front does not suffer from the ABA problem. Even assuming
we've got a function that adds new values, we can never get a new value of
head the same as the old one. This is an additional benefit of using
std::shared_ptr: the old node is kept alive as long as one thread holds a
pointer. So, thread X reads head and gets a pointer to node A. This node is
now kept alive until thread X destroys or reassigns that pointer. That means
that no new node can be allocated with the same address, so if head is equal
to the value p then it really must be the same node, and not just some
imposter that happens to share the same address.
Lock-freedom
I mentioned earlier that implementations may use a mutex to provide the
synchronization in atomic_shared_ptr. They may also manage to make it
lock-free. This can be tested using the is_lock_free() member function common
to all the C++ atomic types.
The advantage of providing a lock-free atomic_shared_ptr should be obvious: by
avoiding the use of a mutex, there is greater scope for concurrency of the
atomic_shared_ptr operations. In particular, multiple concurrent reads can
proceed unhindered.
The downside will also be apparent to anyone with any experience with lock-free code: the code is more complex, and has more work to do, so may be slower in the uncontended cases. The other big downside of lock-free code (maintenance and correctness) is passed over to the implementor!
It is my belief that the scalability benefits outweight the complexity, which is
why Just::Thread v2.2 will ship with a lock-free
atomic_shared_ptr implementation.
Posted by Anthony Williams
[/ threading /] permanent link
Tags: cplusplus, concurrency, multithreading
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
10th Anniversary Sale - last few days
Wednesday, 29 July 2015
The last few days of our 10th Anniversary Sale are upon us. Just::Thread and Just::Thread Pro are available for 50% off the normal price until 31st July 2015.
Just::Thread is our implementation of the C++11 and C++14 thread libraries, for Windows, Linux and MacOSX. It also includes some of the extensions from the upcoming C++ Concurrency TS, with more to come shortly.
Just::Thread Pro is our add-on library which provides an Actor framework for easier concurrency, along with concurrent data structures: a thread-safe queue, and concurrent hash map, and a wrapper for ensuring synchronized access to single objects.
All licences include a free upgrade to point releases, so if you purchase now you'll get a free upgrade to all 2.x releases.
Coming soon in v2.2
The V2.2 release of Just::Thread will be out soon. This will include the new facilities from the Concurrency TS:
Some features from the concurrency TS are already in V2.1:
All customers with V2.x licenses, including those purchased during the sale, will get a free upgrade to V2.2 when it is released.
Posted by Anthony Williams
[/ news /] permanent link
Tags: sale
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
std::shared_ptr's secret constructor
Friday, 24 July 2015
std::shared_ptr has a secret: a constructor that most users don't even know
exists, but which is surprisingly useful. It was added during the lead-up to the
C++11 standard, so wasn't in the TR1 version of shared_ptr, but it's been
shipped with gcc since at least gcc 4.3, and with Visual Studio since Visual
Studio 2010, and it's been in Boost since at least v1.35.0.
This constructor doesn't appear in most tutorials on std::shared_ptr. Nicolai
Josuttis devotes half a page to this constructor in the second edition of The
C++ Standard Library, but Scott Meyers doesn't even mention it in his item on
std::shared_ptr in Effective Modern C++.
So: what is this constructor? It's the aliasing constructor.
Aliasing shared_ptrs
What does this secret constructor do for us? It allows us to construct a new
shared_ptr instance that shares ownership with another shared_ptr, but which
has a different pointer value. I'm not talking about a pointer value that's just
been cast from one type to another, I'm talking about a completely different
value. You can have a shared_ptr<std::string> and a shared_ptr<double> share
ownership, for example.
Of course, only one pointer is ever owned by a given set of shared_ptr
objects, and only that pointer will be deleted when the objects are
destroyed. Just because you can create a new shared_ptr that holds a different
value, you don't suddenly get the second pointer magically freed as well. Only
the original pointer value used to create the first shared_ptr will be
deleted.
If your new pointer values don't get freed, what use is this constructor? It
allows you to pass out shared_ptr objects that refer to subobjects and keep
the parent alive.
Sharing subobjects
Suppose you have a class X with a member that is an instance of some class Y:
struct X{
Y y;
};
Now, suppose you have a dynamically allocated instance of X that you're
managing with a shared_ptr<X>, and you want to pass the Y member to a
library that takes a shared_ptr<Y>. You could construct a shared_ptr<Y> that
refers to the member, with a do-nothing deleter, so the library doesn't actually
try and delete the Y object, but what if the library keeps hold of the
shared_ptr<Y> and our original shared_ptr<X> goes out of scope?
struct do_nothing_deleter{
template<typename> void operator()(T*){}
};
void store_for_later(std::shared_ptr<Y>);
void foo(){
std::shared_ptr<X> px(std::make_shared<X>());
std::shared_ptr<Y> py(&px->y,do_nothing_deleter());
store_for_later(py);
} // our X object is destroyed
Our stored shared_ptr<Y> now points midway through a destroyed object, which
is rather undesirable. This is where the aliasing constructor comes in: rather
than fiddling with deleters, we just say that our shared_ptr<Y> shares
ownership with our shared_ptr<X>. Now our shared_ptr<Y> keeps our X object
alive, so the pointer it holds is still valid.
void bar(){
std::shared_ptr<X> px(std::make_shared<X>());
std::shared_ptr<Y> py(px,&px->y);
store_for_later(py);
} // our X object is kept alive
The pointer doesn't have to be directly related at all: the only requirement is
that the lifetime of the new pointer is at least as long as the lifetime of the
shared_ptr objects that reference it. If we had a new class X2 that held a
dynamically allocated Y object we could still use the aliasing constructor to
get a shared_ptr<Y> that referred to our dynamically-allocated Y object.
struct X2{
std::unique_ptr<Y> y;
X2():y(new Y){}
};
void baz(){
std::shared_ptr<X2> px(std::make_shared<X2>());
std::shared_ptr<Y> py(px,px->y.get());
store_for_later(py);
} // our X2 object is kept alive
This could be used for classes that use the pimpl idiom, or trees where you
want to be able to pass round pointers to the child nodes, but keep the whole
tree alive. Or, you could use it to keep a shared library alive as long as a
pointer to a variable stored in that library was being used. If our class X
loads the shared library in its constructor and unloads it in the destructor,
then we can pass round shared_ptr<Y> objects that share ownership with our
shared_ptr<X> object to keep the shared library from being unloaded until all
the shared_ptr<Y> objects have been destroyed or reset.
The details
The constructor signature looks like this:
template<typename Other,typename Target>
shared_ptr(shared_ptr<Other> const& other,Target* p);
As ever, if you're constructing a shared_ptr<T> then the pointer p must be
convertible to a T*, but there's no restriction on the type of Other at
all. The newly constructed object shares ownership with other, so
other.use_count() is increased by 1, and the value returned by get() on the
new object is static_cast<T*>(p).
There's a slight nuance here: if other is an empty shared_ptr, such as a
default-constructed shared_ptr, then the new shared_ptr is also empty, and
has a use_count() of 0, but it has a non-NULL value if p was not
NULL.
int i;
shared_ptr<int> sp(shared_ptr<X>(),&i);
assert(sp.use_count()==0);
assert(sp.get()==&i);
Whether this odd effect has any use is open to debate.
Final Thoughts
This little-known constructor is potentially very useful for passing around
shared_ptr objects that reference parts of a non-trivial data structure and
keep the whole data structure alive. Not everyone will need it, but for those
that do it will avoid a lot of headaches.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: shared_ptr, cplusplus
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
All the world's a stage... C++ Actors from Just::Thread Pro
Wednesday, 15 July 2015
Handling shared mutable state is probably the single hardest part of writing multithreaded code. There are lots of ways to address this problem; one of the common ones is the actors metaphor. Going back to Hoare's Communicating Sequential Processes, the idea is simple - you build your program out of a set of actors that send each other messages. Each actor runs normal sequential code, occasionally pausing to receive incoming messages from other actors. This means that you can analyse the behaviour of each actor independently; you only need to consider which messages might be received at each receive point. You could treat each actor as a state machine, with the messages triggering state transitions.
This is how Erlang processes work: each process is an actor, which runs independently from the other processes, except that they can send messages to each other. Just::thread Pro: Actors Edition adds library facilities to support this to C++. In the rest of this article I will describe how to write programs that take advantage of it. Though the details will differ, the approach can be used with other libraries that provide similar facilities, or with the actor support in other languages.
Simple Actors
Actors are embodied in the
jss::actor
class. You pass in a function or other callable object (such as a lambda
function) to the constructor, and this function is then run on a background
thread. This is exactly the same as for
std::thread,
except that the destructor waits for the actor thread to finish, rather than
calling std::terminate.
void simple_function(){
std::cout<<"simple actor\n";
}
int main(){
jss::actor actor1(simple_function);
jss::actor actor2([]{
std::cout<<"lambda actor\n";
});
}
The waiting destructor is nice, but it's really a side issue — the main benefit of actors is the ability to communicate using messages rather than shared state.
Sending and receiving messages
To send a message to an actor you just call the
send()
member function on the actor object, passing in whatever message you wish to
send. send() is a function template, so you can send any type of message
— there are no special requirements on the message type, just that it is a
MoveConstructible type. You can also use the stream-insertion operator to send
a message, which allows easy chaining e.g.
actor1.send(42);
actor2.send(MyMessage("some data"));
actor2<<Message1()<<Message2();
Sending a message to an actor just adds it to the actor's message queue. If the
actor never checks the message queue then the message does nothing. To check the
message queue, the actor function needs to call the
receive()
static member function of
jss::actor. This
is a static member function so that it always has access to the running actor,
anywhere in the code — if it were a non-static member function then you
would need to ensure that the appropriate object was passed around, which would
complicate interfaces, and open up the possibility of the wrong object being
passed around, and lifetime management issues.
The call to jss::actor::receive() will then block the actor's thread until a
message that it can handle has been received. By default, the only message type
that can be handled is jss::stop_actor. If a message of this type is sent to
an actor then the receive() function will throw a jss::stop_actor
exception. Uncaught, this exception will stop the actor running. In the
following example, the only output will be "Actor running", since the actor will
block at the receive() call until the stop message is sent, and when the message
arrives, receive() will throw.
void stoppable_actor(){
std::cout<<"Actor running"<<std::endl;
jss::actor::receive();
std::cout<<"This line is never run"<<std::endl;
}
int main(){
jss::actor a1(stoppable_actor);
std::this_thread::sleep_for(std::chrono::seconds(1));
a1.send(jss::stop_actor());
}
Sending a "stop" message is common-enough that there's a special member function
for that too:
stop(). "a1.stop()"
is thus equivalent to "a1.send(jss::stop_actor())".
Handling a message of another type requires that you tell the receive() call
what types of message you can handle, which is done by chaining one or more
calls to the
match()
function template. You must specify the type of the message to handle, and then
provide a function to call if the message is received. Any messages other than
jss::stop_actor not specified in a match() call will be removed from the queue,
but otherwise ignored. In the following example, only messages of type "int" and
"std::string" are accepted; the output is thus:
Waiting
42
Waiting
Hello
Waiting
Done
Here's the code:
void simple_receiver(){
while(true){
std::cout<<"Waiting"<<std::endl;
jss::actor::receive()
.match<int>([](int i){std::cout<<i<<std::endl;})
.match<std::string>([](std::string const&s){std::cout<<s<<std::endl;});
}
}
int main(){
{
jss::actor a(simple_receiver);
a.send(true);
a.send(42);
a.send(std::string("Hello"));
a.send(3.141);
a.send(jss::stop_actor());
} // wait for actor to finish
std::cout<<"Done"<<std::endl;
}
It is important to note that the receive() call will block until it receives
one of the messages you have told it to handle, or a jss::stop_actor message,
and unexpected messages will be removed from the queue and discarded. This means
the actors don't accumulate a backlog of messages they haven't yet said they can
handle, and you don't have to worry about out-of-order messages messing up a
receive() call.
These simple examples have just had main() sending messages to the actors. For
a true actor-based system we need them to be able to send messages to each
other, and reply to messages. Let's take a look at how we can do that.
Referencing one actor from another
Suppose we want to write a simple time service actor, that sends the current
time back to any other actor that asks it for the time. At first thought it
looks rather simple: write a simple loop that handles a "time request" message,
gets the time, and sends a response. It won't be that much different from our
simple_receiver() function above:
struct time_request{};
void time_server(){
while(true){
jss::actor::receive()
.match<time_request>([](time_request r){
auto now=std::chrono::system_clock::now();
????.send(now);
});
}
}
The problem is, we don't know which actor to send the response to — the
whole point of this time server is that it will respond to a message from any
other actor. The solution is to pass the sender as part of the message. We could
just pass a pointer or reference to the jss::actor instance, but that requires
that the actor knows the location of its own controlling object, which makes it
more complicated — none of the examples we've had so far could know that,
since the controlling object is a local variable declared in a separate
function. What is needed instead is a simple means of identifying an actor,
which the actor code can query — an actor reference. The type of an actor
reference is
jss::actor_ref,
which is implicitly constructible from a jss::actor. An actor can also obtain
a reference to itself by calling
jss::actor::self(). jss::actor_ref
has a
send()
member function and stream insertion operator for sending messages, just like
jss::actor. So, we can put the sender of our time_request message in the message
itself as a jss::actor_ref data member, and use that when sending the response.
struct time_request{
jss::actor_ref sender;
};
void time_server(){
while(true){
jss::actor::receive()
.match<time_request>([](time_request r){
auto now=std::chrono::system_clock::now();
r.sender<<now;
});
}
}
void query(jss::actor_ref server){
server<<time_request{jss::actor::self()};
jss::actor::receive()
.match<std::chrono::system_clock::time_point>(
[](std::chrono::system_clock::time_point){
std::cout<<"time received"<<std::endl;
});
}
Dangling references
If you use jss::actor_ref then you have to be prepared for the case that the
referenced actor might have stopped executing by the time you send the
message. In this case, any attempts to send a message through the
jss::actor_ref instance will throw an exception of type
[jss::no_actor]http://www.stdthread.co.uk/prodoc/headers/actor/no_actor.html. To
be robust, our time server really ought to handle that too — if an
unhandled exception of any type other than jss::stop_actor escapes the actor
function then the library will call std::terminate. We should therefore wrap the
attempt to send the message in a try-catch block.
void time_server(){
while(true){
jss::actor::receive()
.match<time_request>([](time_request r){
auto now=std::chrono::system_clock::now();
try{
r.sender<<now;
} catch(jss::no_actor&){}
});
}
}
We can now set up a pair of actors that play ping-pong:
struct pingpong{
jss::actor_ref sender;
};
void pingpong_player(std::string message){
while(true){
try{
jss::actor::receive()
.match<pingpong>([&](pingpong msg){
std::cout<<message<<std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
msg.sender<<pingpong{jss::actor::self()};
});
}
catch(jss::no_actor&){
std::cout<<"Partner quit"<<std::endl;
break;
}
}
}
int main(){
jss::actor ping(pingpong_player,"ping");
jss::actor pong(pingpong_player,"pong");
ping<<pingpong{pong};
std::this_thread::sleep_for(std::chrono::seconds(1));
ping.stop();
pong.stop();
}
This will give output along the lines of the following:
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
ping
pong
Partner quit
The sleep in the player's message handler is to slow everything down — if
you take it out then messages will go back and forth as fast as the system can
handle, and you'll get thousands of lines of output. However, even at full speed
the pings and pongs will be interleaved, because sending a message synchronizes
with the receive() call that receives it.
That's essentially all there is to it — the rest is just application design. As an example of how it can all be put together, let's look at an implementation of the classic sleeping barber problem.
The Lazy Barber
For those that haven't met it before, the problem goes like this: Mr Todd runs a barber shop, but he's very lazy. If there are no customers in the shop then he likes to go to sleep. When a customer comes in they have to wake him up if he's asleep, take a seat if there is one, or come back later if there are no free seats. When Mr Todd has cut someone's hair, he must move on to the next customer if there is one, otherwise he can go back to sleep.
The barber actor
Let's start with the barber. He sleeps in his chair until a customer comes in, then wakes up and cuts the customer's hair. When he's done, if there is a waiting customer he cuts that customer's hair. If there are no customers, he goes back to sleep, and finally at closing time he goes home. This is shown as a state machine in figure 1.
This translates into code as shown in listing 1.The wait
loops for "sleeping" and "cutting hair" have been combined, since almost the
same set of messages is being handled in each case — the only difference
is that the "cutting hair" state also has the option of "no customers", which
cannot be received in the "sleeping" state, and would be a no-op if it was. This
allows the action associated with the "cutting hair" state to be entirely
handled in the lambda associated with the customer_waiting message; splitting
the wait loops would require that the code was extracted out to a separate
function, which would make it harder to keep count of the haircuts. Of course,
if you don't have a compiler with lambda support then you'll need to do that
anyway. The logger is a global actor that receives std::strings as messages
and writes them to std::cout. This avoids any synchronization issues with
multiple threads trying to write out at once, but it does mean that you have to
pre-format the strings, such as when logging the number of haircuts done in the
day. The code for this is shown in listing 2.
The customer actor
Let's look at things from the other side: the customer. The customer goes to town, and does some shopping. Each customer periodically goes into the barber shop to try and get a hair cut. If they manage, or the shop is closed, then they go home, otherwise they do some more shopping and go back to the barber shop later. This is shown in the state machine in figure 2.
This translates into the code in listing 3. Note that the customer
interacts with a "shop" actor that I haven't mentioned yet. It is often
convenient to have an actor that represents shared state, since this allows
access to the shared state from other actors to be serialized without needing an
explicit mutex. In this case, the shop holds the number of waiting customers,
which must be shared with any customers that come in, so they know whether there
is a free chair or not. Rather than have the barber have to deal with messages
from new customers while he is cutting hair, the shop acts as an
intermediary. The customer also has to handle the case that the shop has already
closed, so the shop reference might refer to an actor that has finished
executing, and thus get a jss::no_actor exception when trying to send
messages.
The message handlers for the shop are short, and just send out further messages to the barber or the customer, which is ideal for a simple state-manager — you don't want other actors waiting to perform simple state checks because the state manager is performing a lengthy operation; this is why we separated the shop from the barber. The shop has 2 states: open, where new customers are accepted provided there are fewer than the remaining spaces, and closed, where new customers are turned away, and the shop is just waiting for the last customer to leave. If a customer comes in, and there is a free chair then a message is sent to the barber that there is a customer waiting; if there is no space then a message is sent back to the customer to say so. When it's closing time then we switch to the "closing" state — in the code we exit the first while loop and enter the second. This is all shown in listing 4.
The messages are shown in listing 5, and the main() function that drives it all is in listing 6.
Exit stage left
There are of course other ways of writing code to deal with any particular scenario, even if you stick to using actors. This article has shown some of the issues that you need to think about when using an actor-based approach, as well as demonstrating how it all fits together with the Just::Thread Pro actors library. Though the details will be different, the larger issues will be common to any implementation of the actor model.
Get the code
If you want to download the code for a better look, or to try it out, you can download it here.
Get your copy of Just:::Thread Pro
If you like the idea of working with actors in your code, now is the ideal time to get Just::Thread Pro. Get your copy now.
This blog post is based on an article that was printed in the July 2013 issue of CVu, the Journal of the ACCU.
Posted by Anthony Williams
[/ threading /] permanent link
Tags: cplusplus, actors, concurrency, multithreading
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
New Concurrency Features in C++14
Wednesday, 08 July 2015
It might have been out for 7 months already, but the C++14 standard is still pretty fresh. The changes include a couple of enhancements to the thread library, so I thought it was about time I wrote about them here.
Shared locking
The biggest of the changes is the addition of
std::shared_timed_mutex. This
is a multiple-reader, single-writer mutex. This means that in addition to the
single-ownership mode supported by the other standard mutexes, you can also lock
it in shared ownership mode, in which case multiple threads may hold a shared
ownership lock at the same time.
This is commonly used for data structures that are read frequently but modified only rarely. When the data structure is stable, all threads that want to read the data structure are free to do so concurrently, but when the data structure is being modified then only the thread doing the modification is permitted to access the data structure.
The timed part of the name is analagous to
std::timed_mutex
and
std::recursive_timed_mutex:
timeouts can be specified for any attempt to acquire a lock, whether a
shared-ownership lock or a single-ownership lock. There is a proposal to add a
plain std::shared_mutex to the next standard, since this can have lower
overhead on some platforms.
To manage the new shared ownership mode there are a new set of member functions:
lock_shared(),
try_lock_shared(),
unlock_shared(),
try_lock_shared_for()
and
try_lock_shared_until(). Obtaining
and releasing the single-ownership lock is performed with the same set of
operations as for std::timed_mutex.
However, it is generally considered bad practise to use these functions directly
in C++, since that leaves the possibility of dangling locks if a code path
doesn't release the lock correctly. It is better to use
std::lock_guard
and
std::unique_lock
to perform lock management in the single-ownership case, and the
shared-ownership case is no different: the C++14 standard also provides a new
std::shared_lock
class template for managing shared ownership locks. It works just the same as
std::unique_lock; for common use cases it acquires the lock in the
constructor, and releases it in the destructor, but there are member functions
to allow alternative access patterns.
Typical uses will thus look like the following:
std::shared_timed_mutex m;
my_data_structure data;
void reader(){
std::shared_lock<std::shared_timed_mutex> lk(m);
do_something_with(data);
}
void writer(){
std::lock_guard<std::shared_timed_mutex> lk(m);
update(data);
}
Performance warning
The implementation of a mutex that supports shared ownership is inherently more
complex than a mutex that only supports exclusive ownership, and all the
shared-ownership locks still need to modify the mutex internals. This means that
the mutex itself can become a point of contention, and sap performance. Whether
using a std::shared_timed_mutex instead of a std::mutex provides better or
worse performance overall is therefore strongly dependent on the work load and
access patterns.
As ever, I therefore strongly recommend profiling your application with
std::mutex and std::shared_timed_mutex in order to ascertain which performs
best for your use case.
std::chrono enhancements
The other concurrency enhancements in the C++14 standard are all in the
<chrono> header. Though this isn't strictly about concurrency, it is used for
all the timing-related functions in the concurrency library, and is therefore
important for any threaded code that has timeouts.
constexpr all round
The first change is that the library has been given a hefty dose of constexpr
goodness. Instances of std::chrono::duration and std::chrono::time_point now
have constexpr constructors and simple arithmetic operations are also
constexpr. This means you can now create durations and time points which are
compile-time constants. It also means they are literal types, which is
important for the other enhancement to <chrono>: user-defined literals for
durations.
User-defined literals
C++11 introduced the idea of user-defined literals, so you could provide a
suffix to numeric and string literals in your code to construct a user-defined
type of object, much as 3.2f creates a float rather than the default
double, however there were no new types of literals provided by the standard
library.
C++14 changes that. We now have user-defined literals for
std::chrono::duration, so you can write 30s instead of
std::chrono::seconds(30). To get this user-defined literal goodness you need
to explicitly enable it in your code with a using directive — you might have
other code that wants to use these suffixes for a different set of types, so the
standard let's you choose.
That using directive is:
using namespace std::literals::chrono_literals;
The supported suffixes are:
h→std::chrono::hoursmin→std::chrono::minutess→std::chrono::secondsms→std::chrono::millisecondsus→std::chrono::microsecondsns→std::chrono::nanoseconds
You can therefore wait for a shared ownership lock with a 50 millisecond timeout like this:
void foo(){
using namespace std::literals::chrono_literals;
std::shared_lock<std::shared_timed_mutex> lk(m,50ms);
if(lk.owns_lock()){
do_something_with_lock_held();
}
else {
do_something_without_lock_held();
}
}
Just::Thread support
As you might expect, Just::Thread provides an
implementation of all of this. std::shared_timed_mutex is available on all
supported platforms, but the constexpr and user-defined literal enhancements
are only available for those compilers that support the new language features:
gcc 4.6 or later for constexpr and gcc 4.7 or later for user-defined
literals, with the -std=c++11 or std=c++14 switch enabled in either case.
Get your copy of Just::Thread while
our 10th anniversary sale is on for a 50% discount.
Posted by Anthony Williams
[/ threading /] permanent link
Tags: cplusplus, concurrency
| Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Design and Content Copyright © 2005-2015 Just Software Solutions Ltd. All rights reserved.



