C++0x allocators - visual-c++

I observed that my copy of MSVC10 came with containers that appeared to allow state based allocators, and wrote a simple pool allocator, that allocates pools for a specific type.
However, I discovered that if _ITERATOR_DEBUG_LEVEL != 0 the MSVC vector creates a proxy allocator from the passed allocator (for iterator tracking?), uses the proxy, then lets the proxy fall out of scope, expecting the allocated memory to remain. This causes problems because my allocator attempts to release it's pool upon destruction. Is this allowed by the C++0x standard?
The code is roughly like this:
class _Container_proxy{};
template<class T, class _Alloc>
class vector {
_Alloc _Alval;
public:
vector() {
// construct _Alloc<_Container_proxy> _Alproxy
typename _Alloc::template rebind<_Container_proxy>::other
_Alproxy(_Alval);
//allocate
this->_Myproxy = _Alproxy.allocate(1);
/*other stuff, but no deallocation*/
} //_Alproxy goes out of scope
~_Vector_val() { // destroy proxy
// construct _Alloc<_Container_proxy> _Alproxy
typename _Alloc::template rebind<_Container_proxy>::other
_Alproxy(_Alval);
/*stuff, but no allocation*/
_Alproxy.deallocate(this->_Myproxy, 1);
} //_Alproxy goes out of scope again

According to the giant table of allocator requirements in section 17.6.3.5, an allocator must be copyable. Containers are allowed to copy them freely. So you need to store the pool in a std::shared_ptr or something similar in order to prevent deletion while one of the allocators is in existence.

Related

Are read_volatile and write_volatile atomic for usize?

I want to use read_volatile and write_volatile for IPC using shared memory. Is it guaranteed that writing of an unsigned integer of usize type will be atomic?
At the time of this writing, Rust does not have a proper memory model, but instead it uses that imposed by the LLVM, that is basically that of C++, that in turn is inherited fom C. So the best references you have of what is guaranteed doing memory stuff is that from C.
In C volatile should not be used for syncronization, its intended use is for memory mapped I/O and maybe for single-threaded signal handlers. See for example this Linux-kernel specific gideline. Or this other description of volatile:
This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution.
If you want to do concurrent access to a value you should use atomics operations. They have the volatile guarantee plus additional ones. They are guaranteed to be atomic even in the presence of concurrent access. And moreover they allow you to set the ordering mode.
For your particular case you should use AtomicUsize. Note that the availability of that type is conditioned on your architecture having the necessary support, but that is exactly what you want.
Note that an AtomicUsize has the same memory layout of a plain usize, so if you have a usize embedded in a shared struct you can access atomically with a pointer cast. I think this code is sound:
struct SharedData {
// ...
x: usize
}
fn test(data: *mut SharedData) {
let x = unsafe { &*(&(*data).x as *const usize as *const AtomicUsize) };
let _ = x.load(Ordering::Relaxed);
}
Although you would be better just declaring that x as AtomicUsize directly.
Also note that reading or writing that value using any non-atomic operation (even just reading it out of curiosity, even using volatile access) invokes Undefined Behavior.

When should I call the free() methods generated by wasm-pack?

I wrote some Rust code and compiled it with wasm-pack. I notice these free() methods in the generated .d.ts files:
export class PdfDoc {
free(): void;
...
}
PdfDoc owns a massive amount of memory, up to 1GB, so it's important that all that memory be properly released for reuse when the javascript code is done with it.
Questions:
When should I call these free() methods?
Do I need to call them explicitly or will they be called automatically?
What happens if I never call them?
I searched for "wasm-pack free method" but these combination of search terms didn't find anything useful.
I was wondering the same thing: do I need to carefully pair each new MyStruct() with a call to free() when using wasm-bindgen?
When should I call these free() methods?
Call free() before losing the last reference to the JS object wrapper instance, or earlier if you are done using the object.
Do I need to call them explicitly or will they be called automatically?
Currently WASM-allocated memory will not free when the JS object wrapper goes out of scope (but s.a. weak references below).
What happens if I never call them?
The WASM memory is lost and without a pointer now you won't be able to recover it. This might not be a problem for a fixed or limited number of smaller sized structs, the whole WASM memory is released on unloading the page.
In more detail:
Looking at the created bindings we see that the memory allocated in the constructors is not tracked elsewhere and effectively lost if we just forget the returned instance (a JS wrapper object that stores the raw pointer as ptr).
The wasm-bindgen Guide also hints to this in Support for Weak References
mentioning that TC39 weak references is not supported/implemented right now (late 2022):
Without weak references your JS integration may be susceptible to memory leaks in Rust, for example:
You could forget to call .free() on a JS object, leaving the Rust memory allocated.
The wasm-bindgen Guide example WebAudio shows the usage of free() to prevent
leaking memory when repeatedly creating objects that go out of scope. There is at most exactly one (active) object remaining, which mostly reflects your use-case:
Cleaning up objects by calling free() when they are not needed anymore and before they go out of scope.
As an additional aside on careful memory management:
There might be a design catch to watch out for when using copy-types, consider:
#[wasm_bindgen]
#[derive(Clone, Copy)]
pub struct Bounds {
width: usize,
height: usize,
}
#[wasm_bindgen]
impl Bounds {
// ...
#[wasm_bindgen(getter)]
pub fn width(&self) -> usize {
self.width
}
}
#[wasm_bindgen]
pub struct MyThing {
bounds: Bounds,
// ...
}
#[wasm_bindgen]
impl MyThing {
// ...
#[wasm_bindgen(getter)]
pub fn bounds(&self) -> Bounds {
self.bounds
}
}
which is easily usual and safe code in Rust but here will leak memory if simply used from JS like
console.log(`Current width is ${myThing.bounds.width} px`);
You might want to watch WASM memory while developing with e.g.
console.log(`WASM memory usage is ${wasm.memory.buffer.byteLength} bytes`);

Static objects in rust

Often times in embedded setting we need to declare static structs (drivers etc) so that
their memory is known and assigned at compile time.
Is there any way to achieve something similar in rust?
For example, I want to have a uart driver struct
struct DriverUart{
...
}
and an associated impl block.
Now, I want to avoid having a function named new(), and instead, I want to somewhere allocate this memory a-priori (or to have a new function that I can call statically outside
any code block).
In C I would simply put an instantiation of this struct in some header file and it will be statically allocated and globally available.
I haven't found any thing similar in rust.
If it is not possible then why? and what is the best why we can achieve something similar?
Thanks!
Now, I want to avoid having a function named new(), and instead, I want to somewhere allocate this memory a-priori (or to have a new function that I can call statically outside any code block). In C I would simply put an instantiation of this struct in some header file and it will be statically allocated and globally available. I haven't found any thing similar in rust. If it is not possible then why? and what is the best why we can achieve something similar?
https://doc.rust-lang.org/std/keyword.static.html
You can do the same in Rust, without the header, as long as all the elements are const:
struct DriverUart {
whatever: u32
}
static thing: DriverUart = DriverUart { whatever: 5 };
If you need to evaluate non-const expressions, then that obviously will not work and you'll need to use something like lazy_static or once_cell to instantiate simili-statics.
And of course, what with Rust being a safe languages and statics being shared state, mutable statics are wildly unsafe if not mitigated via thread-safe interior-mutability containers (e.g. an atomic, or a Mutex though those are currently non-const, and it's unclear if they can ever be otherwise), a static is considered to always be shared between threads.

Static member with static mutex and thread-safety

I have a template class similar to this one:
template <typename T>
class Foo {
public:
static void show () {
unique_lock<mutex> l {mtx};
for (const auto& v : vec) {
cout << v << endl;
}
}
static void add (T s) {
unique_lock<mutex> l {mtx};
vec.push_back (s);
}
private:
static mutex mtx;
static vector<T> vec;
};
template <typename T> mutex Foo<T>::mtx;
template <typename T> vector<T> Foo<T>::vec;
And usage of this class looks like this:
Foo<string>::add ("d");
Foo<string>::add ("dr");
Foo<string>::add ("dre");
Foo<string>::add ("drew");
Foo<string>::show ();
Could you tell me if this class is thread-safe? And if it is not, how to make a thread safe version?
If I understand it correctly when we have a class with member functions (not static) and mutex (not static), we prevent race condition of the single object which has been passed across threads, right? And when we have something similar to this we prevent race condition not for the object but for the class instead - in this case for particular type, or am I wrong?
Looks good to me. Up and to a point.
mtx is 'guarding' vec to ensure that the iteration in show() can not be taking place while the vector is being modified during add().
Consider calling it vec_mtx if that is its role.
Up and to a point?
Firstly, your use doesn't (in fact) indicate any threading taking place so I don't (quite) know what you're trying to achieve.
For example if all those adds were taking place in one thread and show in another, your code (obviously) won't ensure that they have all taken place before show.
It will only ensure that (logically) it takes place either before all of them, strictly between two of them or after all of them.
Although not applicable to your use case if you retained references to string objects you passed in or used a type T with a 'shallow' copy constructor then you might be in trouble.
Consider Foo::add(buffer); and continue modifying buffer such that show() is executing in one thread while strcat(buffer,.) is executing on another and buffer is temporarily not '\0' terminated. Boom! Book a ticket to Seg Fault City (where the grass aint green and the girls aint pretty).
You need to look hard (real hard) at what data is being shared and how.
Almost all unqualified statements 'X is thread-safe' are false for all X.
You should always (always) qualify what uses they are safe for and/or how far their safety extends.
That goes 10 times for templates.
Almost all template 'guarantees' can be blown by using some kind of C array (or complex structure holding a pointer or referenced elsewhere, passing it into template in a thread here while smacking it about over there. Your efforts to make an internal copy will themselves be unsafe!
There's a recurring fallacy that if you share data through some kind of thread-safe exchange structure such as a queue you get some kind of thread-safe guarantee and you never need to think about it again and can go back to your single threaded thinking.
Here endeth the lesson.
NB: In theory std::string could be implemented on a memory starved environment that aggressively 'pools' copy strings in a way that exposes you to race conditions you haven't even imagined. Theory you understand.

Thread local boost fast_pool_allocator

I've a multithreaded (Cilk) program where each thread use a temporary
std::set. There are a lot of allocations on these std::set so that I'm
trying to use some pool allocators namely boost::fast_pool_allocator:
using allocator = boost::fast_pool_allocator< SGroup::type >;
using set = std::set<SGroup::type, std::less<SGroup::type>, allocator>;
But now the performances are much worse because of concurrent access to the
allocator. One crucial fact is that the sets are never communicated among the
threads so that I can use a thread local allocators. However, as shown in the
previous code, I'm not constructing allocator objects but passing template
parameters to the std::set constructor.
So here is my question: is it possible to construct multiple
boost::fast_pool_allocator to use them as thread local pool allocator ?
Edit : I removed stupid std::pair allocations.
EDIT
Mmm. I had an answer here that I pieced together from things I remembered seeing. However, upon further inspection it looks like all the allocators actually work with Singleton Pools that are never thread safe without synchronization. In fact, the null_mutex is likely in a detail namespace for this very reason: it only makes sense to use it if you know the program doesn't use threads (well, outisde the main thread) at all.
Aside from this apparent debacle, you could probably use object_pool directly. But it's not an allocator, so it wouldn't serve you for your container example.
Original Answer Text:
You can pass an allocator instance at construction:
#include <boost/pool/pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/thread.hpp>
#include <set>
struct SGroup
{
int data;
typedef int type;
};
using allocator = boost::fast_pool_allocator<SGroup::type>;
using set = std::set<SGroup::type, std::less<SGroup::type>, allocator>;
void thread_function()
{
allocator alloc; // thread local
set myset(set::key_compare(), alloc);
// do stuff
}
int main()
{
boost::thread_group group;
for (int i = 0; i<10; ++i)
group.create_thread(thread_function);
group.join_all();
}
Let me read the docs on how to disable thread-awareness on the allocator :)
Found it in an example:
typedef boost::fast_pool_allocator<SGroup::type,
boost::default_user_allocator_new_delete,
boost::details::pool::null_mutex> allocator;
The example in boost/libs/pool/example/time_pool_alloc.hpp should help you get started benchmarking the difference(s) in performance

Resources