Opened 13 years ago

Closed 13 years ago

#3407 closed Bugs (wontfix)

boost::call_once not re-entrant (at least in win32)

Reported by: Vincent Falco <thevinn@…> Owned by: Anthony Williams
Milestone: Boost 1.41.0 Component: thread
Version: Boost 1.40.0 Severity: Problem
Keywords: threads Cc:

Description

The win32 implementation of boost::call_once ( boost/thread/win32/once.hpp version 1.40.0 ) is not reentrant for the same thread. The problem happens on line 127. The function is called, and then the flag is set. This order should be reversed, the flag should be set and then the function should be called. If the function throws, the flag must be set back.

This program demonstrates the issue:

#include <boost/thread/once.hpp>

static boost::once_flag flag;

void called_twice() {

boost::call_once( called_twice, flag );

gets here twice

}

int main() {

boost::call_once( called_twice, flag );

}

While this may seem like a contrived example, it can easily happen in practice. Consider the case of a boost::singleton constructor that calls a function which then accesses its 'instance' member. The result will be that the singleton is created twice, because call_once is not re-entrant.

Also consider the case of two singletons, A and B. A calls methods on B from its constructor, and B calls methods on A from its constructor. A will be created twice due to the non-reentrant behavior of call_once.

I have not studied the behavior of call_once for other platforms.

Change History (4)

comment:1 by Steven Watanabe, 13 years ago

The flag must be set after the function is called. The reason is that if another thread calls call_once, it should block until the function is completed. I'll also point out that there is no good behavior for a recursive call to call_once. If it calls the function again, then f will be called twice. If it does not, then whatever initialization that call_once is doing may be incomplete. In either case, you have to know whether a call can be recursive and carefully design for it. If it happens accidentally, you're probably toast regardless of how it behaves. In the face of recursive calls it is impossible to maintain the post-condition that the function has run exactly once.

comment:2 by viboes, 13 years ago

As this works as expected, Anthony could just add on the documentation why re-entrant call_once functions are not a good idea? The explanation of Steven could be a good starting point.

comment:3 by viboes, 13 years ago

Component: threadsthread

comment:4 by Anthony Williams, 13 years ago

Resolution: wontfix
Status: newclosed

Documentation updated, changeset 57862

Note: See TracTickets for help on using tickets.