views:

191

answers:

2

Hey,

I've been writing a multi-threaded DLL for database access using ADO/ODBC for use with a legacy application. I need to keep multiple database connections for each thread, so I've put the ADO objects for each connection in an object and thinking of keeping an array of them inside a custom threadInfo object. Obviously a vector would serve better here - I need to delete/rearrange objects on the go and a vector would simplify that. Problem is, I'm allocating a heap for each thread to avoid heap contention and stuff and allocating all my memory from there.

So my question is: how do I make the vector allocate from the thread-specific heap? (Or would it know internally to allocate memory from the same heap as its wrapper class - sounds unlikely, but I'm not a C++ guy) I've googled a bit and it looks like I might need to write an allocator or something - which looks like so much of work I don't want. Is there any other way? I've heard vector uses placement-new for all its stuff inside, so can overloading operator new be worked into it?

My scant knowledge of the insides of C++ doesn't help, seeing as I'm mainly a C programmer (even that - relatively). It's very possible I'm missing something elementary somewhere. If nothing easier comes up - I might just go and do the array thing, but hopefully it won't come to that.

I'm using MS-VC++ 6.0 (hey, it's rude to laugh! :-P ).

Any/all help will be much appreciated.

+3  A: 

how do I make the vector allocate from the thread-specific heap?

You pass it (at compile-time) an appropriate allocator. Here is a classic on how to do so. If you follow that article's advice (or even just copy the code and adapt it where needed), for a C programmer writing an allocator might be easier than getting right the copy semantics of a class with a dynamically allocated array.

Note that, if you put objects into the vector (or your own array, FTM), which themselves use the heap (strings, for example), you need to take that they use your special heap, too. For containers of the standard library (std::basic_string<> is such a container) it's easy since you can pass them your allocator as well. For your own types you have to make that sure yourself.

And try to get away from VC6 as fast as possible. It's poisonous.

sbi
Yeah, I'd come upon this before. Frankly they started with "don't use this to overload new[] ... there's no reason to use an allocator in a normal code" and that kinda put me off. Checking it out again, now.The objects in the vector will use the specific heap, yeah. I've already made sure of that. Didn't know about the template of basic_string, so thanks! (Though apart from the vector I've been careful to keep all the members as primitives.)Meanwhile, waiting to see if any other answer comes up!
Deep-B
@Deep-B: I guess having to put object on a special heap just doesn't count as "normal code" anymore, so that's no argument in your case. `:)` As for strings in C++: There is a `typedef basic_string<char> string` (within namspace `std`, or course) in the standard library's `<string>` header. `std::basic_string` has two more template parameters which default to `std::char_traits<CharType>` and `std::allocator<CharType>`. If you `typedef std::basic_string<char, std::char_traits<char>, my_allocator<char> > my_string_type` you have something similar to `std::string`, but using your own heap.
sbi
A: 

Look up __declspec

The following code declares an integer thread local variable and initializes it with a value:

__declspec( thread ) int tls_i = 1;

On another note. It is not a good idea to keep ADO connections open for a long time. You'll get into a lot of issues with db connectivity. They'll appear open to the application. However, they will bomb out with a "General network error" message when you send a query across.

It's better to close the connection as soon as possible through your app and rely on the connection pool managed by the OS.

Also, depending on the number of clients connecting to the db, you may hit the maximum number of sockets open on the server side. This is from memory. Once a connection is closed on the client side, the connection on the server goes into a TIME_WAIT state. By default, the server socket takes about 4 minutes to close, so it is not available to other clients during that time. The bottom line is that there is a limited number of available sockets on the server. Keeping too many connections open can create a problem.

Sorry, got way off topic there.

Chris Bednarski
Sorry, can't use that - __declspec is :1> broken for OSs before Vista (Vista actually FIXED something?!!!!); 2> fails (UB, I think) if you call the dll functions through LoadLibrary(). I've already decided on using TLS indices after some research on this.... And I'm not sure how this answer is pertinent, seeing I'm talking about an object... but thanks anyway.
Deep-B
Sorry, I meant __declspec(thread), not __declspec. Obviously. :P
Deep-B
Hm, unfortunately that (the connection lifetime) is not in my hands. The dll just gives the legacy app an interface to fire queries on databases it has no other way of contacting. I might put your advice into the usage FAQ though - for the guys who're actually going to code the caller programs.Thanks for the info about the timing stuff. Seems I need to do some more research... as well as testing the dll under some really heavy load once it's finished...
Deep-B
One project I worked on easily hit the socket limit with around 120 users. A new 'feature' was added that absolutely hammered the server, and after a few hours of using the app, things would suddenly slow to a crawl for everyone. SQL server was not closing enough sockets in time for new connection requests. Although there are 65K sockets altogether, only the first 5000 are made available to the ADO (this is a default registry setting thing, so can be changed).
Chris Bednarski
The number of sockets in TIME_WAIT state would slowly build up until the OS would not allocate any more. So clients had to wait until server side sockets closed and a new connection could then be created.
Chris Bednarski
Definitely something for the Other One to keep in mind, lol. Thanks for the ADO info! :-)
Deep-B