Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Anthony Williams

Pages: 1 2 3 [4] 5 6
46
General Discussion about just::thread / Re: unaligned atomic variables
« on: February 17, 2011, 02:30:12 PM »
Are you suggesting putting assert(variable_correctly_aligned()); statements inside the atomic operations? If so, then that seems a reasonable idea.

47
I am pleased to announce that version 1.5.0 of just::thread, our C++0x Thread Library has just been released.

This release heralds official support for Debian Lenny and Squeeze, and Fedora 13 and 14; no longer are Linux developers restricted to Ubuntu.

This version has also been updated to match the latest C++ working draft. The resultant changes are:

  • There is a new launch policy for std::async: std::launch::deferred. This replaces std::launch::sync, and indicates that the supplied function should be run in the thread that calls get() or wait() on the resultant future rather than asynchronously on its own thread. std::launch::sync is still supported for backwards compatibility.
  • There is a new clock type: std::chrono::steady_clock. This replaces std::chrono::monotonic_clock, and is guaranteed to be continuously increasing at a steady rate. This is the clock used for duration-based timeouts. std::chrono::monotonic_clock is still supported for backwards compatibility.
  • std::atomic_future has been removed from the standard draft. It is therefore deprecated in just::thread, though still supported for backwards compatibility.
  • std::future has a new member function share() for easy conversion to std::shared_future. This works well with the new C++0x use of auto, when you know you want to get a std::shared_future from a std::promise, std::packaged_task or std::async call:
Code: [Select]
int some_function();
std::shared_future<int> f(std::async(some_function)); // old syntax
auto f2=std::async(some_function).share(); // new syntax

This release also provides support for std::atomic<char16_t> and std::atomic<char32_t>, where char16_t and char32_t are provided by the underlying platform.

48
Well-spotted. I'll add that for V1.5.1

49
General Discussion about just::thread / Re: Thread Local Storage
« on: February 03, 2011, 03:02:40 PM »
Maybe. boost::thread_specific_ptr is slightly different again: though each pointer is freed automatically, you have to manually allocate and construct the object for each thread.
It is, but at least it allows to have thread local objects and not to worry about freeing it up afterwards, which is simply impossible with __declspec(thread).
As far as I know boost::thread_specific is handled in special way in boost::thread calling procedure, so I can't use boost::thread_specific in std::thread, is it right?

You should be able to use boost::thread_specific_ptr alongside std::thread. boost::thread_specific_ptr provides automatic cleanup for non-boost threads for the compilers supported by just::thread. On Windows, you might have to use the DLL version of boost, though, since the static library might clash with the just::thread library for the automatic cleanup hook.

50
General Discussion about just::thread / Re: Thread Local Storage
« on: February 03, 2011, 02:46:54 PM »
Currently I'm using compilers support for TLS, but both GCC and MSVC have the same issue, they don't allow to have objects with non-trivial constructor in thread local storage, as far as I understood from C++ Concurrency in Action examples this is allowed in C++0x

Yes, in C++0x thread_local variables can be types with non-trivial constructors and destructors.

maybe something like boost::thread_specific would be more useful here?

Maybe. boost::thread_specific_ptr is slightly different again: though each pointer is freed automatically, you have to manually allocate and construct the object for each thread.

51
General Discussion about just::thread / Re: Thread Local Storage
« on: February 03, 2011, 02:25:26 PM »
There is currently no support for TLS in just::thread. Given that the compilers supported by just::thread do have TLS support, I will consider adding it for a future release.

52
memory_order_acq_rel - which is again no-op on x86
Prevents compiler and hardware from reordering loads with load part of operation and stores with store part of operation.
Operation with memory_order_acq_rel flag means
atomic_thread_fence(memory_order_release);
operation();
atomic_thread_fence(memory_order_acquire);


A atomic_thread_fence(memory_order_acq_rel) on x86 is just a signal to the compiler not to reorder instructions across it, since any following loads already have an acquire fence, and preceding stores have a release fence.

memory_order_acq_rel is also a no-op when applied to atomic RMW operations on x86. Some RMW instructions (such as XCHG) automatically have full memory_order_seq_cst semantics. Others (such as CMPXCHG) need the LOCK prefix to make them atomic --- without the LOCK prefix they are just a load followed by a store rather than atomic RMW op --- but then they too have full memory_order_seq_cst semantics.

Now, on page 18 of above mentioned article Bartosz says that Peterson Lock is an example of algorithm, which will not work without fences. However, Peterson's lock uses only acquire, release and acq-rel.
http://www.justsoftwaresolutions.co.uk/threading/petersons_lock_with_C++0x_atomics.html
If those operations are no-op on x86 then Peterson Lock has to work on x86 without any fence. Am I wrong somewhere?

Peterson's lock can be implemented either with an explicit fence, or by using an RMW operation with memory_order_acq_rel instead of a plain store to turn --- in Dmitriy's implementation on that page, the result of the call to turn.exchange() is not used; the exchange is done purely for the ordering properties of the RMW op. If a plain store is used, or the RMW operation is done on the wrong variable, then the guarantees required by the algorithm are not provided (as explained in the analysis on that page). You could use an explicit fence instead (which probably needs to be a memory_order_seq_cst fence, but I haven't worked it all through.)

For Dekker's algorithm it's clear, it uses sequentially consistent memory fence, so it requires fencing on x86 too, but what about Peterson lock?

Quote
though such a fence can also be achieved with a LOCKed RMW instruction, such as XCHG.
On Visual Studio MemoryBarrier() function is implemented as a not locked RMW instruction.
http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
Quote
LONG Barrier;
__asm {
     xchg Barrier, eax
}
Is it a typeo in MSDN?

No, it's not a typo: XCHG and LOCK XCHG are equivalent.


Quote
Plain loads and stores on x86 give you acquire (for loads) and release (for stores) ordering. This is sufficient for many algorithms, but not for others. LFENCE and SFENCE are primarily of use with non-temporal stores such as MOVNTI, which don't obey the normal cache coherency rules (that's what "non-temporal" means, in effect --- they don't occur at a particular time).
So it means that there is no analogs for sfence and lfence in C++1x, is it right?

That's right. A call to atomic_thread_fence(memory_order_seq_cst) will provide the required ordering, because it's a full fence, but you'd have to code your non-temporal stores in assembly anyway. The same applies to WC (Write Combining) memory pages --- loads from and stores to such pages are always relaxed, and you need an explicit fence to force an ordering, but you'd need assembly language or a special OS call to create such memory pages.

53
Yes, plain loads have acquire semantics and plain stores have release semantics on x86. Note that actually, the ordering on the data variable are superfluous and could be replaced with std::memory_order_relaxed: the operations on ready are sufficient to guarantee the ordering.
Does it mean that fences are completely unneccessary on x86? In the article mentioned above I can see this
Quote
There must be algorithms that require fences even on the x86.
and there are mfence, sfence and lfence instructions available on x86. How does your library work if it doesn't use them and where they are used? Could you please explain this in more details?

Plain loads and stores on x86 give you acquire (for loads) and release (for stores) ordering. This is sufficient for many algorithms, but not for others. LFENCE and SFENCE are primarily of use with non-temporal stores such as MOVNTI, which don't obey the normal cache coherency rules (that's what "non-temporal" means, in effect --- they don't occur at a particular time).

MFENCE can be used as a full memory barrier, akin to atomic_thread_fence(memory_order_seq_cst), though such a fence can also be achieved with a LOCKed RMW instruction, such as XCHG.

Dekker's algorithm for mutual exclusion requires such ordering. See http://www.justsoftwaresolutions.co.uk/threading/implementing_dekkers_algorithm_with_fences.html for an example implementation, and a description of the required memory ordering constraints.

54
The current release supports gcc 4.5 (if you install the right .debs); older releases did not, and the message was correct when written. I guess I ought to update the readme and documentation.

55
General Discussion about just::thread / Re: std::kill_dependency
« on: December 17, 2010, 09:32:12 AM »
The dependency ordering stuff only matters where memory_order_consume is distinct from memory_order_acquire. This is not the case for x86 systems, which is the only type of processor currently supported by just::thread. std::kill_dependency is thus a no-op, and is provided for completeness only.

56
General Discussion about just::thread / Re: mutex as class member
« on: December 14, 2010, 03:35:26 PM »
It does help, thanks for replying :)

You're welcome

This issue of the non-copy mutex really interests me.
I can't help wondering why it is non-copyable.
Is this issue to do with whether the mutex would be a deep vs shallow copy of the mutex ?
What danger or mischief is prevented by making a mutex non-copyable ?

What does it mean to copy a mutex? Do you copy the lock state, so the same thread owns the lock as owned the original? If so, how does that thread know? I do not know of an OS that provides copyable mutexes. You might have a copyable handle to a mutex, which is equivalent to a pointer, but then all copies of the handle share the same underlying mutex.

When copying an object with a mutex, you probably want to create a new mutex for the new object rather than share the mutex, and the new mutex probably ought to be created unlocked, rather than copying the lock state. However, you probably do want to lock the mutex on the source object whilst you're copying, in order to avoid a data race on the other data members.

Java has a unique intrinsic lock built into every object of every class.
To the best of knowledge, there are no special hazards associated with this scenario.
(but of-course, i don't know, what i don't know)

It's true that you can synchronize on any object in Java, but most implementations will not create a mutex for every object --- they may share mutexes between objects or create them lazily on demand.

Also, in Java you do not copy most objects, you just pass round pointers instead. If you want to clone an object then you need to ensure that it is correctly synchronized.

Anthony

57
General Discussion about just::thread / Re: mutex as class member
« on: December 13, 2010, 08:29:19 AM »
consider this simple class (shown below)

It's just a callable functor class, implementing the func. call operator.
I find that when i declare a mutex inside this class, the compiler curses me...
.. uttering words like:

/usr/include/justthread/mutex: In copy constructor ‘functor::functor(const functor&)’:
threadId.cxx:19:   instantiated from ‘__jss::__0x::__invoker<_ResultType, _Callable, _Args>::__invoker(_Callable&, const __jss::__0x::__args_tuple<_OtherArgs ...>&) [with _OtherArgs = , _ResultType = void, _Callable = functor&, _Args = ]’

When i make the mutex global (line 17).. the code compiles and runs as expected.
I also tried wrapping the mutex in a unique_lock.  But ... no joy.

Is it not possible to define a mutex as a class member ?
Any suggestions.. warmly welcomed :)
Quote

std::mutex is not copyable. That means that if you define a mutex as a class member then the compiler cannot implicitly define the copy constructor, and you get an error message like the one you show when you try and copy your class.

If you want to make your class copyable then you need to write a copy constructor that default-constructs the mutex. You might also want to lock the mutex on the source whilst you do the copy, so that you don't get a race condition.

However, if you are copying your functor onto a thread then you probably don't need a mutex, as the thread will be the only place that can access the copy that was running on the thread, so no synchronization is needed. The fact that you think you need synchronization suggests you intend to access the same object from multiple threads, in which case you probably want to pass the functor by reference using std::ref (or std::tr1::ref if std::ref is not available):

Code: [Select]
functor f;
std::thread t(std::ref(f));

Hope that helps,

Anthony

58
General Discussion about just::thread / Re: deadlock detection
« on: September 07, 2010, 10:42:05 PM »
I have updated the online documentation at http://www.stdthread.co.uk/doc/deadlockdebug.html

59
General Discussion about just::thread / Re: deadlock detection
« on: September 07, 2010, 03:14:56 PM »
Oops. The documentation needs updating.  :(

You need to ensure that the just::thread headers are being used, and that the checked version of the library is being linked.

Code: [Select]
g++ -std=c++0x -pthread -I/usr/include/justthread -D_JUST_THREAD_DEADLOCK_CHECK -g -rdynamic -o sample_deadlockcheck sample_deadlock.cpp -ljustthread_check
If you don't link against the checked version of the library then you'll get linker errors if the include path is set up correctly.

Also, if you move the lock in main() to before the creation of the thread then you'll get a deadlock every time:

Code: [Select]
#include <thread>
#include <mutex>
#include <iostream>

std::mutex io_mutex;

void thread_func()
{
    std::lock_guard<std::mutex> lk(io_mutex);
    std::cout<<"Hello from thread_func"<<std::endl;
}

int main()
{
    std::lock_guard<std::mutex> lk(io_mutex);
    std::thread t(thread_func);
    std::cout<<"Hello from main thread"<<std::endl;
    t.join();
    return 0;
}

60
And just for clarity: just::thread does not support g++ 4.5 or later in the current release.

Pages: 1 2 3 [4] 5 6