From: Chris Thomasson on
"xushiwei" <xushiweizh(a)gmail.com> wrote in message
news:52ee8318-2611-4883-bbef-33c9a566bb75(a)s50g2000hsb.googlegroups.com...
> On 4��22��, ����9ʱ52��, "Chris Thomasson" <cris...(a)comcast.net> wrote:
>> "Chris Thomasson" <cris...(a)comcast.net> wrote in message
>>
>> If I am correct, well, "perhaps" I have something that just might be able
>> to
>> help your allocator. There is an invention that can transform most
>> single-threaded memory allocators into scaleable multi-threaded ones;
>> here
>> is my initial post:
>>
>> http://groups.google.com/group/comp.arch/browse_frm/thread/6dc825ec99...
>>
>> basically, you create single-threaded allocator and plug it into the
>> system,
>> then, boom, its multi-threaded. If you have any questions, feel free to
>> fire
>> away...
>
>
> I'm sorry but I think you misunderstand my points. I don't want to
> create single-threaded allocator.
>
> Why? Sharing GC Allocator in multi threads is not recommended. It
> means that sharing memory between threads is also not recommended. If
> you REALLY want to share memory, use new/delete or anything else.
>
> For users of GC Allocator, we suggest that only use ONE BlockPool
> instance in ONE thread, and ONE thread may use multiple PRIVATE
> "ScopeAlloc" instances (depend on your requirement) to allocate
> memory.
[...]

You did create a purely single-threaded allocator. Your saying that I need
to create an allocator instance per-thread, but I cannot do cross thread
deallocations using them because they provide no support for
synchronization. Did you know that there are multi-threaded allocators that
are based on per-thread heaps? Check StreamFlow or Hoard documentation. If I
use those allocators I can allocate memory in Thread A and deallocate in
Thread A without any synchronization whatsoever, however, if I deallocate in
Thread B then there is an interlocked RMW instruction. This aspect makes
them more flexible. For your own words, I cannot create a simple
producer/consumer pattern using your algorithm because they are not
thread-safe.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: xushiwei on
{ Please do not quote extraneous material, such as the clc++m banner.
Please also note that top posting is discouraged in this group. -mod }

Yes, GC Allocator is not thread-safe. It's my EMPHASES in
implementation section. And that is
why GC Allocator is so fast.

I don't think implementing a producer/consumer pattern is a common
case. So, why not implement an allocator without a multithreaded lock,
then use it with a explicit lock when you implement a producer/
consumer pattern (or something that need to share memory)?

On 4��22��, ����5ʱ39��, "Chris Thomasson" <cris...(a)comcast.net> wrote:
> "xushiwei" <xushiwe...(a)gmail.com> wrote in message
>
> AFAICT, your implementation is not thread-safe. For instance, I could not
> use it to implement a producer/consumer pattern. Thread A allocates blocks
> and passes them to thread B which frees them. Am I missing something?

{ banner removed -mod }

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Michael Kilburn on
On Apr 22, 4:13 am, xushiwei <xushiwe...(a)gmail.com> wrote:
> To obtain a copy of this paper in pdf format click here (http://
> xushiwei.com/local--files/gc-allocator/GCAllocator.pdf or from google
> code:http://code.google.com/p/stdext/downloads/list). Another copy is
> also available on google docs (http://docs.google.com/View?
> docid=dds5zgx6_353dc5k4fcq) in html format.
[ the rest skipped]

Had a look at your code... Looks unnecessarily complicated to me. Here
is the result of about 15 minutes of work:

[code]
#include <deque>
#include <cassert>


using namespace std;


struct FastAlloc
{
struct Block
{
unsigned char memory[1024];
};
deque<Block> m_pool;
size_t m_left;

FastAlloc() : m_left(0) {}

void* allocate(size_t size)
{
assert(size <= 1024);
if (size > m_left)
{
m_pool.resize(m_pool.size() + 1);
m_left = 1024;
}

void* res = m_pool.back().memory + 1024 - m_left;
m_left -= size;
return res;
}
};


template<class T>
class my_alloc
{
public:
FastAlloc* m_alloc;
typedef T value_type;

typedef value_type* pointer;
typedef value_type& reference;
typedef value_type const* const_pointer;
typedef value_type const& const_reference;

typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;

template<class _Other>
struct rebind
{ // convert an my_alloc<_Ty> to an my_alloc <_Other>
typedef my_alloc<_Other> other;
};

pointer address(reference _Val) const
{ // return address of mutable _Val
return pointer(&_Val);
}

const_pointer address(const_reference _Val) const
{ // return address of nonmutable _Val
return const_pointer(&_Val);
}
/*
my_alloc()
{ // construct default my_alloc (do nothing)
}
*/

my_alloc(FastAlloc& alloc) : m_alloc(&alloc)
{ // construct default my_alloc (do nothing)
}

my_alloc(const my_alloc<T>& o)
{ // construct by copying (do nothing)
m_alloc = o.m_alloc;
}

template<class _Other>
my_alloc(const my_alloc<_Other>& o)
{ // construct from a related my_alloc (do nothing)
m_alloc = o.m_alloc;
}

template<class _Other>
my_alloc<T>& operator=(const my_alloc<_Other>&)
{ // assign from a related my_alloc (do nothing)
m_alloc = o.m_alloc;
return (*this);
}

void deallocate(pointer _Ptr, size_type)
{ // deallocate object at _Ptr, ignore size
}

pointer allocate(size_type _Count, const void _FARQ * = 0)
{ // allocate array of _Count elements, ignore hint
return pointer(m_alloc->allocate(_Count*sizeof(T)));
}

void construct(pointer _Ptr, T const& _Val)
{ // construct object at _Ptr with value _Val
new (_Ptr) T(_Val);
}

void destroy(pointer _Ptr)
{ // destroy object at _Ptr
(*_Ptr).~T();
}

std::size_t max_size() const
{ // estimate maximum array size
std::size_t _Count = (std::size_t)(-1) / sizeof (T);
return (0 < _Count ? _Count : 1);
}
};

int main()
{
FastAlloc alloc;

deque<int, my_alloc<int> > q(alloc);

q.push_back(1024);
return 1;
}
[/code]

add STD_NEW/STD_DELETE support, parametrize my_alloc with allocator
type, write few different allocator classes and that's it. Looks much
more simple.

Sincerely yours,
Michael.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]