473,395 Members | 1,694 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

What's the connection between objects and threads?

Hi

I have to write a multi-threaded program. I decided to take an OO
approach to it. I had the idea to wrap up all of the thread functions
in a mix-in class called Threadable. Then when an object should run
in its own thread, it should implement this mix-in class. Does this
sound like plausible design decision?

I'm surprised that C++ doesn't have such functionality, say in its
STL. This absence of a thread/object relationship in C++ leads me to
believe that my idea isn't a very good one.

I would appreciate your insights. thanks
Jun 27 '08
167 8115
On May 28, 3:30*pm, Gerhard Fiedler <geli...@gmail.comwrote:
On 2008-05-27 10:52:21, kwikius wrote:
In this environment preemptive multitasking doesnt seem to make much
sense, although it seems to be what we have with a messy fight by
threads to take control of some slice of shared memory at some arbitrary
time and lock out other threads who might to try to grab it at any time.

There are situations where one application needs to serve several
asynchronous events (for example a web server). In a cooperative
multitasking scheme the application is required to periodically poll each
device that may create an event. With preemptive multitasking, threads can
just wait for an event, and leave the actual communication mechanism to the
asynchronous event source up to the OS (which may poll a device, or react
to a hardware interrupt, or whatever).
But see http://www.kegel.com/c10k.html for a critique of using
preemptive
threads for scalable event driven applications (in particular web
servers).

--
Giovanni P. Deretta
Gerhard
Jun 27 '08 #151

"gpderetta" <gp*******@gmail.comwrote in message
news:27**********************************@b1g2000h sg.googlegroups.com...
On May 27, 3:52 pm, kwikius <a...@servocomm.freeserve.co.ukwrote:

<...>

The problem is that kernel space is hostile. The kernel just allocates
memory and services requests but has no real interest in what the
application is doing. The application is competing with other
applications and has no real incentive to call yield, it only makes
the app look slower. IOW cooperative multitasking doesnt work in
kernel space, the only solution then is preemptive multitasking, which
is a blunt instrument, but pragmatic.

yes, more or less this is the situation.
>
Within an application however cooperative multitasking seems to make a
lot of sense. The application adds up to a common whole and its parts
are designed to cooperate. Its a friendly environment not a hostile
one. In this environment preemptive multitasking doesnt seem to make
much sense, although it seems to be what we have with a messy fight by
threads to take control of some slice of shared memory at some
arbitrary time and lock out other threads who might to try to grab it
at any time.


It still makes sense if you need one or more of these situations:
- need take advantage of multiple CPU for parallelism (no way to do
cooperative multitasking there and still get any reasonable
parallelism),
Well heres my current insight

Separate nonshared data by space -execute in parallel
Separate shared data by time -execute sequentially

That requires a top down approach, IOW a scheduler, but a scheduler can
separate processes either by space or by time intelligently only if the
scheduler knows about the application semantics, IOW runs in application
space.

Currently the usual option is a scheduler that runs in kernel space and
there is no cooperation with the application.

regards
Andy Little


Jun 27 '08 #152

"kwikius" <an**@servocomm.freeserve.co.ukwrote in message
news:48**********@mk-nntp-2.news.uk.tiscali.com...
>
"gpderetta" <gp*******@gmail.comwrote in message
news:27**********************************@b1g2000h sg.googlegroups.com...
On May 27, 3:52 pm, kwikius <a...@servocomm.freeserve.co.ukwrote:

<...>
>
The problem is that kernel space is hostile. The kernel just allocates
memory and services requests but has no real interest in what the
application is doing. The application is competing with other
applications and has no real incentive to call yield, it only makes
the app look slower. IOW cooperative multitasking doesnt work in
kernel space, the only solution then is preemptive multitasking, which
is a blunt instrument, but pragmatic.

yes, more or less this is the situation.
> >
Within an application however cooperative multitasking seems to make a
lot of sense. The application adds up to a common whole and its parts
are designed to cooperate. Its a friendly environment not a hostile
one. In this environment preemptive multitasking doesnt seem to make
much sense, although it seems to be what we have with a messy fight by
threads to take control of some slice of shared memory at some
arbitrary time and lock out other threads who might to try to grab it
at any time.


It still makes sense if you need one or more of these situations:
- need take advantage of multiple CPU for parallelism (no way to do
cooperative multitasking there and still get any reasonable
parallelism),

Well heres my current insight

Separate nonshared data by space -execute in parallel
Separate shared data by time -execute sequentially

That requires a top down approach, IOW a scheduler, but a scheduler can
separate processes either by space or by time intelligently only if the
scheduler knows about the application semantics, IOW runs in application
space.

Currently the usual option is a scheduler that runs in kernel space and
there is no cooperation with the application.
hmm maybe not ...

http://msdn.microsoft.com/en-us/library/aa175393.aspx

hadnt read that when I wrote the original :-)

regards
Andy Little

Jun 27 '08 #153
In article <48********@mk-nntp-2.news.uk.tiscali.com>,
an**@servocomm.freeserve.co.uk says...

[ ... ]
My only thought was that it would be cool if I had control of the thread
scheduler and all threads communicated with the scheduler. The scheduler
keeps a data structure for each thread which is basically read only as far
as the scheduler is concerned Each thread has a yield_to_scheduler(
my_thread_id, mystate) primitive which means that when it has done some
significant work it suspends and its data structure is updated (The data
structure per thread would probably be as simple a I have now completed
step3 of my process or whatever). The scheduler then can block progress of
other threads or start other threads dependent on the current state it sees.
If you want to play with this under Windows, look up fibers. I doubt
it's used much anymore, but at one time there was a package named
cthreads for Unix and similar systems. I'm pretty sure with a little bit
of looking, you can probably find it.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 27 '08 #154

"Jerry Coffin" <jc*****@taeus.comwrote in message
news:MP************************@news.sunsite.dk...
In article <48********@mk-nntp-2.news.uk.tiscali.com>,
an**@servocomm.freeserve.co.uk says...

[ ... ]
>My only thought was that it would be cool if I had control of the thread
scheduler and all threads communicated with the scheduler. The scheduler
keeps a data structure for each thread which is basically read only as
far
as the scheduler is concerned Each thread has a yield_to_scheduler(
my_thread_id, mystate) primitive which means that when it has done some
significant work it suspends and its data structure is updated (The data
structure per thread would probably be as simple a I have now completed
step3 of my process or whatever). The scheduler then can block progress
of
other threads or start other threads dependent on the current state it
sees.

If you want to play with this under Windows, look up fibers. I doubt
it's used much anymore, but at one time there was a package named
cthreads for Unix and similar systems. I'm pretty sure with a little bit
of looking, you can probably find it.
Actually I think I have wandered way O.T. for c.l.c++
Apologies...

regards
Andy Little

Jun 27 '08 #155
"gpderetta" <gp*******@gmail.comwrote in message
news:db**********************************@b1g2000h sg.googlegroups.com...
On May 28, 3:30 pm, Gerhard Fiedler <geli...@gmail.comwrote:
On 2008-05-27 10:52:21, kwikius wrote:
In this environment preemptive multitasking doesnt seem to make much
sense, although it seems to be what we have with a messy fight by
threads to take control of some slice of shared memory at some
arbitrary
time and lock out other threads who might to try to grab it at any
time.
There are situations where one application needs to serve several
asynchronous events (for example a web server). In a cooperative
multitasking scheme the application is required to periodically poll
each
device that may create an event. With preemptive multitasking, threads
can
just wait for an event, and leave the actual communication mechanism to
the
asynchronous event source up to the OS (which may poll a device, or
react
to a hardware interrupt, or whatever).
But see http://www.kegel.com/c10k.html for a critique of using
preemptive
threads for scalable event driven applications (in particular web
servers).
Humm... How is using 60,000 user-threads on a 8-CPU box different from using
highly efficient state-machine and thread-pool algorithms driven by an
average of 16 or so kernel-threads? Before you answer, please realize that
IMVHO, state-machines and shared memory multi-threading are not all that
complicated...

Jun 27 '08 #156
On May 30, 9:24 am, "Chris Thomasson" <cris...@comcast.netwrote:
"gpderetta" <gpdere...@gmail.comwrote in message

news:db**********************************@b1g2000h sg.googlegroups.com...
On May 28, 3:30 pm, Gerhard Fiedler <geli...@gmail.comwrote:
On 2008-05-27 10:52:21, kwikius wrote:
In this environment preemptive multitasking doesnt seem to make much
sense, although it seems to be what we have with a messy fight by
threads to take control of some slice of shared memory at some
arbitrary
time and lock out other threads who might to try to grab it at any
time.
There are situations where one application needs to serve several
asynchronous events (for example a web server). In a cooperative
multitasking scheme the application is required to periodically poll
each
device that may create an event. With preemptive multitasking, threads
can
just wait for an event, and leave the actual communication mechanism to
the
asynchronous event source up to the OS (which may poll a device, or
react
to a hardware interrupt, or whatever).
But seehttp://www.kegel.com/c10k.htmlfor a critique of using
preemptive
threads for scalable event driven applications (in particular web
servers).

Humm... How is using 60,000 user-threads on a 8-CPU box different from using
highly efficient state-machine and thread-pool algorithms driven by an
average of 16 or so kernel-threads? Before you answer, please realize that
IMVHO, state-machines and shared memory multi-threading are not all that
complicated...
There is nothing complicated with shared memory nor state machines. I
object to gratuitous use of preemption.

IMHO there isn't much difference between using _cooperative_ threads
or a pure callback based approach on top of a state machine. Sometimes
the former makes more sense, sometimes the other.
More often, it is better to use both of them and chose on a case by
case basis.

Certainly I wouldn't even think of using 60000 preemptive threads.

--
gpd
Jun 27 '08 #157
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:70**********************************@m36g2000 hse.googlegroups.com...
On May 22, 1:55 am, "Chris Thomasson" <cris...@comcast.netwrote:
"darren" <minof...@gmail.comwrote in message

news:70**********************************@c19g2000 prf.googlegroups.com...
Hi
I have to write a multi-threaded program. I decided to take an OO
approach to it. I had the idea to wrap up all of the thread functions
in a mix-in class called Threadable. Then when an object should run
in its own thread, it should implement this mix-in class. Does this
sound like plausible design decision?
I'm surprised that C++ doesn't have such functionality, say in its
STL. This absence of a thread/object relationship in C++ leads me to
believe that my idea isn't a very good one.
I would appreciate your insights. thanks

Here is a helper object you can use to run objects that provide a specific
interface (e.g., foo::start/join):
__________________________________________________ _______________
[...]
__________________________________________________ _______________

To create and start an object in one step you do:
[...]
>
However, other than perhaps some syntactic-sugar, I don't think that this
gives any advantages over Boost's method of representing and creating
threads...

Any thoughts?
I do think it has advantages over Boost's method. One such advantage
is the RAII nature of it.
Okay. Good point.

Furthermore, I think it should be taken in into the C++0x standard on
the similar grounds as they provide higher level condition variable
wait API as well:
[...]
However, one further improvement could be nice, and in that case it
would be quite a general solution, if one could just denote which
method of the object one wants to start as a process.
Check this out Szabolcs:
__________________________________________________ ___________________
#include <cstdio>


/* Active Object Helper
__________________________________________________ ____________*/
template<
typename T,
void (T::*T_fp_start) () = &T::start,
void (T::*T_fp_join) () = &T::join
struct active {
T object;

struct guard {
T& object;

guard(T& _object) : object(_object) {
(object.*T_fp_start)();
}

~guard() {
(object.*T_fp_join)();
}
};

active() {
(object.*T_fp_start)();
}

~active() {
(object.*T_fp_join)();
}
};


/* Sample usage
__________________________________________________ ____________*/
struct foo1 {
foo1() {
std::printf("(%p)->foo1::foo1()\n", (void*)this);
}

~foo1() throw() {
std::printf("(%p)->foo1::~foo1()\n", (void*)this);
}

void start() {
std::printf("(%p)->void foo1::start()\n", (void*)this);
}

void join() {
std::printf("(%p)->void foo1::join()\n", (void*)this);
}
};
struct foo2 {
foo2() {
std::printf("(%p)->foo2::foo2()\n", (void*)this);
}

~foo2() throw() {
std::printf("(%p)->foo2::~foo2()\n", (void*)this);
}

void run() {
std::printf("(%p)->void foo2::run()\n", (void*)this);
}

void wait() {
std::printf("(%p)->void foo2::wait()\n", (void*)this);
}
};
struct foo3 {
foo3() {
std::printf("(%p)->foo3::foo3()\n", (void*)this);
}

~foo3() throw() {
std::printf("(%p)->foo3::~foo3()\n", (void*)this);
}

void spawn() {
std::printf("(%p)->void foo3::spawn()\n", (void*)this);
}

void join() {
std::printf("(%p)->void foo3::join()\n", (void*)this);
}
};
struct foo4 {
foo4() {
std::printf("(%p)->foo4::foo4()\n", (void*)this);
}

~foo4() throw() {
std::printf("(%p)->foo4::~foo4()\n", (void*)this);
}

void activate() {
std::printf("(%p)->void foo4::activate()\n", (void*)this);
}

void deactivate() {
std::printf("(%p)->void foo4::deactivate()\n", (void*)this);
}
};
int main() {
{
foo4 _foo4;
active<foo1_foo1;
active<foo2, &foo2::run, &foo2::wait_foo2;
active<foo3, &foo3::spawn_foo3;
active<foo4, &foo4::activate, &foo4::deactivate>::guard __foo4(_foo4);
}
std::puts("\n\npress <ENTERto exit...");
std::getchar();
return 0;
}

__________________________________________________ ___________________

All objects with an interface of `T::start/join()' can simply use the
following syntax:
{
active<objecto;
}

Other objects which have a custom function to start as a process could do
something like:

{
active<object, &object::start_my_processo;
}


Furthermore, object which have a custom function to start a process, and a
custom function to join with it could do:

{
active<object, &object::start_my_process, &object::join_my_processo;
}

Do you have any other suggestions on how to further improve the `active<T>'
helper object?

Jun 27 '08 #158
On Jun 3, 3:37*pm, "Chris Thomasson" <cris...@comcast.netwrote:
Do you have any other suggestions on how to further improve the `active<T>'
helper object?
Well, it is getting better and better.

The next problem is how you can handle active objects that have
arguments in their constructors. Just think about a simple producer-
consumer problem. Suppose you have the classes Buffer, Producer, and
Consumer. Then you want to define the access rights among these
objects and define the instance from class Buffer as a passive object,
but the instances from classes Producer and Consumer should be active
objects:

{
Buffer b;
active<Producerp(b);
active<Consumerc(b);
}

Best Regards,
Szabolcs
Jun 27 '08 #159
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:d8**********************************@27g2000h sf.googlegroups.com...
On Jun 3, 3:37 pm, "Chris Thomasson" <cris...@comcast.netwrote:
Do you have any other suggestions on how to further improve the
`active<T>'
helper object?
Well, it is getting better and better.
The next problem is how you can handle active objects that have
arguments in their constructors. Just think about a simple producer-
consumer problem. Suppose you have the classes Buffer, Producer, and
Consumer. Then you want to define the access rights among these
objects and define the instance from class Buffer as a passive object,
but the instances from classes Producer and Consumer should be active
objects:
{
Buffer b;
active<Producerp(b);
active<Consumerc(b);
}

Okay Szabolcs; here ya go:
__________________________________________________ __________________
#include <cstdio>


/* Active Object
__________________________________________________ ____________*/
template<
typename T,
void (T::*T_fp_start) () = &T::start,
void (T::*T_fp_join) () = &T::join
struct active {
T object;

struct guard {
T& object;

guard(T& _object) : object(_object) {
(object.*T_fp_start)();
}

~guard() {
(object.*T_fp_join)();
}
};

active() {
(object.*T_fp_start)();
}

template<typename T_p1>
active(T_p1& p1) : object(p1) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1& p1, T_p1& p2) : object(p1, p2) {
(object.*T_fp_start)();
}

// [and on and on for more and more parameters...]

~active() {
(object.*T_fp_join)();
}
};


/* Sample usage
__________________________________________________ ____________*/
struct Buffer {
Buffer() {
std::printf("(%p)->Buffer::Buffer()\n", (void*)this);
}

~Buffer() {
std::printf("(%p)->Buffer::~Buffer()\n", (void*)this);
}
};
struct Producer {
Buffer& m_Buffer;

Producer(Buffer& _Buffer) : m_Buffer(_Buffer) {
std::printf("(%p)->Producer::Producer()\n", (void*)this);
}

~Producer() {
std::printf("(%p)->Producer::~Producer()\n", (void*)this);
}

void start() {
std::printf("(%p)-void Producer::start() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}

void join() {
std::printf("(%p)-void Producer::join() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}
};
struct Consumer {
Buffer& m_Buffer;

Consumer(Buffer& _Buffer) : m_Buffer(_Buffer) {
std::printf("(%p)->Consumer::Consumer()\n", (void*)this);
}

~Consumer() {
std::printf("(%p)->Consumer::~Consumer()\n", (void*)this);
}

void start() {
std::printf("(%p)-void Consumer::start() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}

void join() {
std::printf("(%p)-void Consumer::join() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}
};
int main() {
{
Buffer b;
active<Producerp(b);
active<Consumerc(b);
}
std::puts("\n\npress <ENTERto exit...");
std::getchar();
return 0;
}

__________________________________________________ __________________


The code compiles on all of my compilers and on Comeau. It allows for the
exact syntax your suggested to be realized. BTW, Thanks for your good
suggestions; they make the template more robust indeed! Now, can you think
of anything else to further enhance my `active<T>' helper template?
:^D

Jun 27 '08 #160
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:kK******************************@comcast.com. ..
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:d8**********************************@27g2000h sf.googlegroups.com...
On Jun 3, 3:37 pm, "Chris Thomasson" <cris...@comcast.netwrote:
>Do you have any other suggestions on how to further improve the
`active<T>'
helper object?
>Well, it is getting better and better.
>The next problem is how you can handle active objects that have
arguments in their constructors. Just think about a simple producer-
consumer problem. Suppose you have the classes Buffer, Producer, and
Consumer. Then you want to define the access rights among these
objects and define the instance from class Buffer as a passive object,
but the instances from classes Producer and Consumer should be active
objects:
>{
Buffer b;
active<Producerp(b);
active<Consumerc(b);
}


Okay Szabolcs; here ya go:
__________________________________________________ __________________
#include <cstdio>


/* Active Object
__________________________________________________ ____________*/
template<
typename T,
void (T::*T_fp_start) () = &T::start,
void (T::*T_fp_join) () = &T::join
>struct active {

T object;

struct guard {
T& object;

guard(T& _object) : object(_object) {
(object.*T_fp_start)();
}

~guard() {
(object.*T_fp_join)();
}
};

active() {
(object.*T_fp_start)();
}

template<typename T_p1>
active(T_p1& p1) : object(p1) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1& p1, T_p1& p2) : object(p1, p2) {
(object.*T_fp_start)();
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^

ARGH! Stupid Fuc%ing bug!
I used the type for parameter 1 in both places! Here is fix:

template<typename T_p1, typename T_p2>
active(T_p1& p1, T_p2& p2) : object(p1, p2) {
(object.*T_fp_start)();
}
Sorry about that non-sense!

;^(....

>
// [and on and on for more and more parameters...]

~active() {
(object.*T_fp_join)();
}
};
[...]
>
__________________________________________________ __________________
Jun 27 '08 #161
On Jun 3, 5:14*pm, "Chris Thomasson" <cris...@comcast.netwrote:
Sorry about that non-sense!
Never mind, getting used to it.

<quote>
Now, can you think
of anything else to further enhance my `active<T>' helper template?
</quote>

I am afraid the parameter specification is not a general solution but
it is better than nothing. I guess it can be improved by some kind of
variadic templates.

I think the last issue to think about is how you can specify a larger
number of of active objects so that they should have their own id. For
instance, how can you specify N producers and M consumers for a
bounded buffer.

If this is solved, it should really be considered by the C++0x
committee, since it would be a huge improvement over the existing
solution with respect to process creation. Having active objects is
the genuine way of combining objects and processes. Besides, it could
be just a higher level construction next to the existing lower level
proposal (similarly to the higher level wait() on the condition
variable).

Still, it is a library level solution and not a language level one, so
everybody can be happy.

Best Regards,
Szabolcs
Jun 27 '08 #162
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:bf**********************************@34g2000h sf.googlegroups.com...
On Jun 3, 5:14 pm, "Chris Thomasson" <cris...@comcast.netwrote:
Sorry about that non-sense!
Never mind, getting used to it.
lol! ;^)

<quote>
Now, can you think
of anything else to further enhance my `active<T>' helper template?
</quote>
I am afraid the parameter specification is not a general solution but
it is better than nothing. I guess it can be improved by some kind of
variadic templates.
Well, its all I could really think of off hand without modifying the end
interface. AFAICT, its fairly generic solution. Why do you seem to think
otherwise?

I think the last issue to think about is how you can specify a larger
number of of active objects so that they should have their own id.
Are you saying that `active<T>' should automatically assign an id?

For
instance, how can you specify N producers and M consumers for a
bounded buffer.
Humm. Could you give a pseudo-code example? Are you talking about
integrating some sort of conditional waits into the mix? Or, are you talking
about a limitation in C++ wrt not being to specify the constructor of each
object in an array? Like:
std::string x[3] = { "One", "Two", "Three" };

AFAICT, that is not valid C++...

If this is solved, it should really be considered by the C++0x
committee, since it would be a huge improvement over the existing
solution with respect to process creation. Having active objects is
the genuine way of combining objects and processes. Besides, it could
be just a higher level construction next to the existing lower level
proposal (similarly to the higher level wait() on the condition
variable).
Still, it is a library level solution and not a language level one, so
everybody can be happy.
Jun 27 '08 #163
On Jun 3, 7:42*pm, "Chris Thomasson" <cris...@comcast.netwrote:
>
std::string x[3] = { "One", "Two", "Three" };

AFAICT, that is not valid C++...
It is. In fact you can actually omit the '3':

std::string x[] = { "One", "Two", "Three" };

HTH,

--
Giovanni P. Deretta

Jun 27 '08 #164
On Jun 3, 7:42*pm, "Chris Thomasson" <cris...@comcast.netwrote:
Humm. Could you give a pseudo-code example?
I mean there are situations where you want to have many entities of
the same kind. E.g. you want to have 5 producers and 3 consumers.
Until the number is small, you can copy paste it like this:

<code_0>
{
Buffer b;
active<Producerp(0, b);
active<Producerp(1, b);
active<Producerp(2, b);
active<Producerp(3, b);
active<Producerp(4, b);
active<Consumerc(0, b);
active<Consumerc(1, b);
active<Consumerc(2, b);
}
</code_0>

Since these are RAII objects, you cannot simply put them into a for or
a while loop, can you? However, obviously we should find some C++
compatible notation to have multiple RAII objects with different
arguments, e.g.:

<pseudocode_1>
{
Buffer b;
active<Producer, 5p(i, b);
active<Consumer, 3c(i, b);
}
</pseudocode_1>

Or not C++ notation:

<pseudocode_2>
{
Buffer b;
foreach int i (0..4) active<Producerp(i, b);
foreach int i (0..2) active<Consumerc(i, b);
}
</pseudocode_2>

Additionally, some general solution would be nice that makes it
possible to have any kind and number of arguments for the active
object and not just an integer id.
Are you talking about
integrating some sort of conditional waits into the mix?
That would come next when we finish with the structured parallel
construction part.

Best Regards,
Szabolcs
Jun 27 '08 #165
"gpderetta" <gp*******@gmail.comwrote in message
news:d2**********************************@l42g2000 hsc.googlegroups.com...
On Jun 3, 7:42 pm, "Chris Thomasson" <cris...@comcast.netwrote:

std::string x[3] = { "One", "Two", "Three" };

AFAICT, that is not valid C++...
It is. In fact you can actually omit the '3':
std::string x[] = { "One", "Two", "Three" };

Man I suck at C++! Thanks for the information.

:^D

Jun 27 '08 #166
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:ab**********************************@25g2000h sx.googlegroups.com...
On Jun 3, 7:42 pm, "Chris Thomasson" <cris...@comcast.netwrote:
Humm. Could you give a pseudo-code example?
I mean there are situations where you want to have many entities of
the same kind. E.g. you want to have 5 producers and 3 consumers.
Until the number is small, you can copy paste it like this:
<code_0>
{
Buffer b;
active<Producerp(0, b);
active<Producerp(1, b);
active<Producerp(2, b);
active<Producerp(3, b);
active<Producerp(4, b);
active<Consumerc(0, b);
active<Consumerc(1, b);
active<Consumerc(2, b);
}
</code_0>
Since these are RAII objects, you cannot simply put them into a for or
a while loop, can you? However, obviously we should find some C++
compatible notation to have multiple RAII objects with different
arguments, e.g.:
Well, check this out; this compiles fine on GCC, Comeau and VC++8/9:
__________________________________________________ _______________________

/* Active Object
__________________________________________________ ____________*/
template<
typename T,
void (T::*T_fp_start) () = &T::start,
void (T::*T_fp_join) () = &T::join
struct active {
T object;

struct guard {
T& object;

guard(T& _object) : object(_object) {
(object.*T_fp_start)();
}

~guard() {
(object.*T_fp_join)();
}
};

active() {
(object.*T_fp_start)();
}

template<typename T_p1>
active(T_p1& p1) : object(p1) {
(object.*T_fp_start)();
}

template<typename T_p1>
active(T_p1 const& p1) : object(p1) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1& p1, T_p2& p2) : object(p1, p2) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1 const& p1, T_p2& p2) : object(p1, p2) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1& p1, T_p2 const& p2) : object(p1, p2) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1 const& p1, T_p2 const& p2) : object(p1, p2) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2, typename T_p3>
active(T_p1 const& p1, T_p2& p2, T_p3& p3)
: object(p1, p2, p3) {
(object.*T_fp_start)();
}

// [and on and on for more and more parameters...]

~active() {
(object.*T_fp_join)();
}
};


/* Sample usage
__________________________________________________ ____________*/
#include <cstdio>
#include <cstddef>
#include <string>

struct Buffer {
Buffer() {
std::printf("(%p)->Buffer::Buffer()\n", (void*)this);
}

~Buffer() {
std::printf("(%p)->Buffer::~Buffer()\n", (void*)this);
}
};
struct Producer {
int const m_id;
std::string const m_name;
Buffer& m_Buffer;

Producer(int const id, Buffer& _Buffer)
: m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) {
std::printf("(%p)->Producer::Producer()\n", (void*)this);
}

Producer(int const id, char const* name, Buffer& _Buffer)
: m_id(id), m_name(name), m_Buffer(_Buffer) {
std::printf("(%p)->Producer::Producer()\n", (void*)this);
}

~Producer() {
std::printf("(%p)->Producer::~Producer()\n", (void*)this);
}

void start() {
std::printf("(%p)-void Producer<'%s'>::start() - Buffer(%p)\n",
(void*)this, m_name.c_str(), (void*)&m_Buffer);
}

void join() {
std::printf("(%p)-void Producer::join() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}
};
struct Consumer {
int const m_id;
std::string const m_name;
Buffer& m_Buffer;

Consumer(int const id, Buffer& _Buffer)
: m_id(id), m_name("Default Consumer"), m_Buffer(_Buffer) {
std::printf("(%p)->Consumer::Consumer()\n", (void*)this);
}

Consumer(int const id, char const* name, Buffer& _Buffer)
: m_id(id), m_name(name), m_Buffer(_Buffer) {
std::printf("(%p)->Consumer::Consumer()\n", (void*)this);
}

~Consumer() {
std::printf("(%p)->Consumer::~Consumer()\n", (void*)this);
}

void start() {
std::printf("(%p)-void Consumer<'%s'>::start() - Buffer(%p)\n",
(void*)this, m_name.c_str(), (void*)&m_Buffer);
}

void join() {
std::printf("(%p)-void Consumer::join() - Buffer(%p)\n",
(void*)this, (void*)&m_Buffer);
}
};
#define ARRAY_DEPTH(mp_this) ( \
sizeof((mp_this)) / sizeof((mp_this)[0]) \
)
int main() {
{
Buffer b;

active<Producerp[] = {
active<Producer>(123, b),
active<Producer>(456, "Custom Producer", b),
active<Producer>(789, b),
active<Producer>(234, "I am a Producer!", b),
active<Producer>(567, b)
};

active<Consumerc[] = {
active<Consumer>(891, "I am a Consumer!", b),
active<Consumer>(345, b),
active<Consumer>(678, b)
};

std::size_t i;

std::puts("-----------------------");

for (i = 0; i < ARRAY_DEPTH(p); ++i) {
std::printf("p[%u].m_id == %d\n", i, p[i].object.m_id);
std::printf("p[%u].m_name == %s\n----\n",
i, p[i].object.m_name.c_str());
}

putchar('\n');

for (i = 0; i < ARRAY_DEPTH(c); ++i) {
std::printf("c[%u].m_id == %d\n", i, c[i].object.m_id);
std::printf("c[%u].m_name == %s\n----\n",
i, c[i].object.m_name.c_str());
}

std::puts("-----------------------");
}
std::puts("\n\npress <ENTERto exit...");
std::getchar();
return 0;
}

__________________________________________________ _______________________
Please take some time to study the code, compile and run it. Please tell me
if this is even remotely close to what your getting at... If not, is it a
decent starting point?


[...]
Are you talking about
integrating some sort of conditional waits into the mix?
That would come next when we finish with the structured parallel
construction part.
We can try.

Jun 27 '08 #167
"Chris Thomasson" <cr*****@comcast.netwrote in message
news:IL******************************@comcast.com. ..
"Szabolcs Ferenczi" <sz***************@gmail.comwrote in message
news:ab**********************************@25g2000h sx.googlegroups.com...
On Jun 3, 7:42 pm, "Chris Thomasson" <cris...@comcast.netwrote:
Humm. Could you give a pseudo-code example?
>I mean there are situations where you want to have many entities of
the same kind. E.g. you want to have 5 producers and 3 consumers.
Until the number is small, you can copy paste it like this:
><code_0>
{
Buffer b;
active<Producerp(0, b);
active<Producerp(1, b);
active<Producerp(2, b);
active<Producerp(3, b);
active<Producerp(4, b);
active<Consumerc(0, b);
active<Consumerc(1, b);
active<Consumerc(2, b);
}
</code_0>
>Since these are RAII objects, you cannot simply put them into a for or
a while loop, can you? However, obviously we should find some C++
compatible notation to have multiple RAII objects with different
arguments, e.g.:

Well, check this out; this compiles fine on GCC, Comeau and VC++8/9:
__________________________________________________ _______________________
[...]
The code as-is compiles and works fine. However, I foresee an ambiguity
problem with some usage scenarios. Here is a version of `active<T>' which
eludes said problem:

template<
typename T,
void (T::*T_fp_start) () = &T::start,
void (T::*T_fp_join) () = &T::join
struct active {
T object;

struct guard {
T& object;

guard(T& _object) : object(_object) {
(object.*T_fp_start)();
}

~guard() {
(object.*T_fp_join)();
}
};

active() {
(object.*T_fp_start)();
}

template<typename T_p1>
active(T_p1 p1) : object(p1) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2>
active(T_p1 p1, T_p2 p2) : object(p1, p2) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2, typename T_p3>
active(T_p1 p1, T_p2 p2, T_p3 p3)
: object(p1, p2, p3) {
(object.*T_fp_start)();
}

template<typename T_p1, typename T_p2, typename T_p3, typename T_p4>
active(T_p1 p1, T_p2 p2, T_p3 p3, T_p4 p4)
: object(p1, p2, p3, p4) {
(object.*T_fp_start)();
}

// [and on and on for more and more parameters...]

~active() {
(object.*T_fp_join)();
}
};


Okay. Well, Szabolcs, what do you think of this corrected version?

Jun 27 '08 #168

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Rob Nicholson | last post by:
I'm starting to worry a bit now. We're getting the above error when two users hit the same database/page on an ASP.NET application using ADO.NET, talking to a SQL 7 server. The error is perfectly...
7
by: Lau Lei Cheong | last post by:
Hello, Actually I think I should have had asked it long before, but somehow I haven't. Here's the scenerio: Say we have a few pages in an ASP.NET project, each of them needs to connect to...
10
by: nephish | last post by:
hey there, i have a huge app that connects to MySQL. There are three threads that are continually connecting and disconnecting to the db. The problem is, if there is an error, it faults out...
10
by: Steven Blair | last post by:
As I understand it, if I create a connection object in my application and close the connection, the next time I open a connection with the same connection string I should be using a pooled...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.