What's the connection between objects and threads?

I

Ian Collins

Szabolcs said:
If you want to be fair then yes, it is your turn. You claimed
something and now you should prove that. You claimed that given the
object launches a thread as the last step in the construction
procedure, it would result in some data race. Please demonstrate what
do you mean. What data race?
I made no such claim.

All I claim is that launching a thread in a constructor invokes
undefined behaviour. Nothing more, nothing less.

You countered with "And the constructor does return. And the object is
fully constructed.". The new thread could run to completion before the
constructor returned, or the constructor could return before the thread
runs. Either is possible and neither is the specified scenario, because
there isn't one.

Do you deny using an incomplete object doesn't invoke undefined behaviour?
 
S

Szabolcs Ferenczi

I'm afraid you have not.

Oh yes, I have. I have copied the fragments here that you cannot
understand still.
 At no point have you shown how to avoid the
new thread running before the object is constructed.

I never wanted to show you anything like that. I even agreed to you
that the thread can start running before the constructor is completed.
I cannot see any poblem with that.

You said you have some problem with that.

What is your problem exactly? It would be good, if instead of trolling
you would prove something finally.

Best Regards,
Szabolcs
 
I

Ian Collins

Szabolcs said:
What is your problem exactly? It would be good, if instead of trolling
you would prove something finally.
I see your true colours have finally come through, insult all who
disagree with you.
 
S

Szabolcs Ferenczi

I made no such claim.

Ok, you did not claim data race.
All I claim is that launching a thread in a constructor invokes
undefined behaviour.  Nothing more, nothing less.

Then you should prove that claim of yours. Nothing more, nothing less.
But do that at last, please.
You countered with "And the constructor does return. And the object is
fully constructed.".  The new thread could run to completion before the
constructor returned,

It depends. If it is a disjoint thread (not likely), yes. And then
nothing wrong is with it. If the thread needs interaction and the
conditions are not met, the thread cannot run to completion before the
constructor returns, of course.
or the constructor could return before the thread
runs.

That is also possible. No problem with that.
 Either is possible and neither is the specified scenario, because
there isn't one.

What do you mean by "neither is the specified scenario, because there
isn't one."? Reference?
Do you deny using an incomplete object doesn't invoke undefined behaviour?

There is no incomplete object. You are mistaken in that.

Let us take class A, you can use any method of class A in the
constructor of class A. (See "Member functions, including virtual
functions (10.3), can be called during construction or destruction")
Agreed?

A thread started as the last step in the constuctor of class A can
equally well call any member of class A. Remember that by convention
(see discipline) members of class A are initialised already. If the
thead would access any object from classes other than A then obviously
those objects are constructed already otherwise the thread would not
have any reference to them.

So, where is your problem? Where are the incomplete objects?

Finally try to prove something, please.

Best Regards,
Szabolcs
 
S

Szabolcs Ferenczi

I see your true colours have finally come through, insult all who
disagree with you.

I try to get some proof out of you instead of you keep trolling.

Besides, I new you would escape instead of proving your claims. It is
the nature of trollers.

Best Regards,
Szabolcs
 
I

Ian Collins

Szabolcs said:
It depends. If it is a disjoint thread (not likely), yes. And then
nothing wrong is with it. If the thread needs interaction and the
conditions are not met, the thread cannot run to completion before the
constructor returns, of course.


That is also possible. No problem with that.


What do you mean by "neither is the specified scenario, because there
isn't one."? Reference?
Well there isn't a reference, because it isn't defined. The C++
standard makes no mention of threads and POSIX for one does not define
the which thread is running after pthread_create. Either the parent,
the child or both may be running after the thread is created.
There is no incomplete object. You are mistaken in that.
I'm not, an object is not complete until its constructor returns.
Let us take class A, you can use any method of class A in the
constructor of class A. (See "Member functions, including virtual
functions (10.3), can be called during construction or destruction")
Agreed?
Provided the virtual function is defined in the class or a base class.
A thread started as the last step in the constuctor of class A can
equally well call any member of class A. Remember that by convention
(see discipline) members of class A are initialised already. If the
thead would access any object from classes other than A then obviously
those objects are constructed already otherwise the thread would not
have any reference to them.

So, where is your problem? Where are the incomplete objects?
Say the constructor uses one or more RAII style objects to manage
resources, even though the thread creation is the last visible call in
the constructor, the managed objects still have to be destroyed. Say
one of these operations fails and throws an exception which isn't
handled in the constructor. The constructor will then throw an
exception and the object's members will be cleaned up and the object
will not have been constructed. But the thread will still be running...
 
K

kasthurirangan.balaji

Thanks for all of the advice.

1. I'm pretty sure creation of many processes is not allowed.  I'll
check though.  It seems like creating a process to handle a request is
much more overhead than a thread though.

2. Thats disturbing news about the discouraging comments on
singletons.  I wish i had known that before I used so many in my
project already.  I have a Logger(), Socket() and UI() singleton
classes, that basically offer static methods to do their job. I
thought the singleton approach was a good idea because I would never
need more than one instance of these things, and this way they can be
accessed from any other object in the program.  For example i have a
static Logger::log() that i can use to log a message from any other
object in the code now.  I'll look into why the singleton approach is
a bad one, but I wouldn't mind some insight here as well.

As for thread pools, Is the basic idea to create a group of threads,
then have them wait on a condition variable?  In my case, when the
server gets a request, it would notify the sleeping threads with a
cond_var, the first thread to then grab the mutex would handle the
request.  This approach seems faulty, as only one thread would ever be
able to grab that mutex and run at any given time.

you may also want to look at www.kegel.com, especially http://www.kegel.com/c10k.html.
also, note that processes vs threads is platform dependent. you may
also look at apache's implementation for freebsd(mpm model).

Thanks,
Balaji.
 
R

Rolf Magnus

ManicQin said:
When you say processes do you mean different processes running
and communicating via files\pipelines\sockets and so on?

Often, you don't have to communicate anything while the child process is
running. On posix systems, fork() is used to create a copy of the process,
so the child knows everything the parent knew when the child was created.
1) Wont it just complicate things?

Actually, I consider it simpler, provided that you don't need to communicate
much after the child has been created. And it has the advantage that if one
of the porcesses crashes, that won't affect the others. In a threaded
program, everything will go down. That's especially important for servers,
which could often go completely without concurrency, but use separate
processes for improved stability.
2) Darren is supposed to submit his project to his prof\tester
usually spliting your projects (IMHO) to sub processes gives it a...
(maybe unjustified) scent of a bad design... Most of my professors
were fixed on the notion that an application is one process. (I think that
spliting your process to subs is a concept that is more acknowledged in
linux \unix platforms then windows.

Not sure what you mean by "splitting your process to subs". Unix
traditionally does many of the things it wants to do parallel with separate
processes. Threads aren't used very often.
Since process creation is much more expensive under Windows, similar
programs need to use threads for performance reasons.
AFAIK it's partially due to the reason that in linux you only
load your code once for all the instances of the application... or
something like
that... CMIIW!!!)

Yes. Copying a process with fork() is very fast. You don't get much of a
performance boost from using threads.
 
I

Ian Collins

Rolf said:
Not sure what you mean by "splitting your process to subs". Unix
traditionally does many of the things it wants to do parallel with separate
processes. Threads aren't used very often.

He used the term "sub processes" earlier in that paragraph.

Well that (Threads aren't used very often) was the case long ago, but
most things in Unix land (including the kernel) make heavy use of threads.
Since process creation is much more expensive under Windows, similar
programs need to use threads for performance reasons.


Yes. Copying a process with fork() is very fast. You don't get much of a
performance boost from using threads.
You do if you have lots or create/destroy them frequently. A thread has
a lot less baggage than a process (especially no Linux has a decent
thread model).
 
J

Jerry Coffin

I was reading this tutorial, and a table in the document describes a
process as being about 50x more expensive than a thread. Maybe I'm
interpreting the table wrong.
https://computing.llnl.gov/tutorials/pthreads/

You seem to be interpreting the table correctly, but may not be
considering how that affects the server as a whole. The fact that one is
50x slower than the other doesn't mean that a server based on that model
would necessarily be 50x slower. Even though one's quite a bit faster
than the other, it creating new threads/processes should be a fairly
small percentage of overall time either way.

Of course, that depends heavily on the rest of the design. Quite a few
people try creating a new thread for every incoming connection. This
would almost certainly be disastrous if you created a new process for
every connection instead.

OTOH, if you create some sort of thread/process pool, then you only
incur that 50x overhead a few times while your server starts up. After
that, you might incur some overhead from inter- rather than intra-
process communication, but that's mostly a separate question.
 
C

Chris Thomasson

Well, he did not point out anything but claimed something. He has
postings that he used to correct the next hour or the next day.

The pseudo-code I post over on 'comp.programming.threads' is all about the
__experimental__ synchronization algorihtms that I am brainstorming. We have
been over this before Szabolcs. If I come up with an idea, I try to make
sure to post it on c.p.t. If there is a typo in the pseudo-code, I promptly
document them and show the corrections. Anyway...



You better read carefully what I have written. I highlighted that one
needs discipline for it. It is hopless for you but at least you calm
down.
I hope I could help though.

Unfortunately, wrt this thread, your so-called help is only going to lead
the OP down the wrong path. You don't seem to get it. AFAICT, the OP wanted
to create a thread base class for users to derive from. Something like:
____________________________________________________________________
class thread_base {
pthread_t m_tid;
virtual void on_entry() = 0;

thread_base() {
}

virtual ~thread_base() throw() = 0;
};

thread_base::~thread_base() throw() {}
____________________________________________________________________





The OP cannot start the thread from the constructor of the base class! This
is what I was referring to. When threads are involved there is a major
race-condition because the thread can be started and call the on_entry pure
virtual function which results in UB. Also, even in the absence of threads
there still can be a problem. Here is a VERY simple example:
____________________________________________________________________
#include <cstdio>
#include <cstdlib>


static void call_abstract_virtual_indirect(class base*);


class base {
friend void call_abstract_virtual_indirect(class base*);
virtual void on_action() = 0;

public:
base() {
call_abstract_virtual_indirect(this);
}

virtual ~base() throw() = 0;
};

base::~base() throw() {}


void call_abstract_virtual_indirect(base* _this) {
_this->on_action();
}




class derived : public base {
int const m_ctor;

public:
derived() : m_ctor(123456789) {

}

private:
void on_action() {
std::printf("(%p)::derived::eek:n_action()\n", (void*)this);
if (m_ctor != 123456789) {
std::printf("(%p)::derived::eek:n_action() - NOT CONSTRUCTED!\n",
(void*)this);
std::getchar();
std::abort();
}
}
};


int main() {
{
derived d;
}


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
std::puts("\n\n____________________________________________\n\
Press <ENTER> to exit...");
std::getchar();
return 0;
}

____________________________________________________________________


The above demonstrates one reason why its generally NOT a good idea to start
a thread in a constructor. Your failure to understand this is only going to
confuse the OP. Your advise is flawed in that respect. The problem produces
undefined-behavior. It can just seg-fault, or it might print "... NOT
CONSTRUCTED!", or whatever. Therefore, I guess the moral of the story is "Do
NOT call abstract virtual functions in constructors!"


:^o
 
C

Chris Thomasson

Ian Collins said:
Well there isn't a reference, because it isn't defined. The C++
standard makes no mention of threads and POSIX for one does not define
the which thread is running after pthread_create. Either the parent,
the child or both may be running after the thread is created.

I'm not, an object is not complete until its constructor returns.

Provided the virtual function is defined in the class or a base class.

Say the constructor uses one or more RAII style objects to manage
resources, even though the thread creation is the last visible call in
the constructor, the managed objects still have to be destroyed. Say
one of these operations fails and throws an exception which isn't
handled in the constructor. The constructor will then throw an
exception and the object's members will be cleaned up and the object
will not have been constructed. But the thread will still be running...

Also, if the threading is implemented as a base class with an abstract
virtual function representing the threads "entry" point, then you simply
cannot create the thread in the constructor. The thread might start running
and call the virtual function before the derived object has even had a
chance to run its ctor; OOPS! This is a major race-condition that Szabolcs
seems to think cannot ever happen. Perhaps I am misunderstanding him,
although, his arguments "seem" to suggest that he is not a C++ programmer...

;^/
 
C

Chris Thomasson

Be aware that although STL is thread-safe to a certain extent,

:^/

Where does the current C++ standard say that the STL is "thread-safe to a
certain extent"???

[...]
 
J

James Kanze

Discipline or not, the practice is best avoided. Even if the
thread is started in the last (visible) instruction in a
constructor, the object is still not fully constructed until
the constructor returns.

Not to mention what happens if someone inherits from your class.
Starting the thread in a constructor is a well known
anti-pattern.
 
J

James Kanze

Ian Collins wrote:
Almost all threaded code I have seen that works in a cross
platform is susceptible to the "problem" in a strict sense.
In practice, if the thread is "enabled" as the very last thing
in the most derived constructor, then there it is very
unlikely you're ever going to see a problem.

And how do you ensure that? About the only way I know is to use
a separate object for the actual thread behavior. This is what
Boost does. (Java uses a separate function to start the thread,
which also works well.)
I have yet to find an alternative that is acceptably straight
forward as this approach.

I'm not sure I understand you. Boost and Java use two radical
different models, yet both manage to avoid the problem.
 
J

James Kanze

The problem is the thread class tends to be used as a base, so
this strict rule breaks down.
I guess I was bitten by it too often in my formative years and
moved to the functor style now adopted by boost. Now I find
the boost style much more straight forward and less fragile.
The object used for the thread is always complete and in a
known state.

That is, IMHO, the cleanest solution. When it comes down to
it, the "object" you execute on isn't the thread; it's used by
the thread, so even from an OO point of view, it seems
preferable.

The alternative is to provide a separate function to start the
thread, as in Java. I personally don't see where this is a
problem either; it's just one additional function call after the
constructor. If the execution object has significant behavior,
it might even be preferable; it gives you a chance to intervene
after the constructor, but before the thread starts (e.g. to
register the object somewhere).

All in all, I don't really believe in the one size fits all
philosophy here, but if I had to stick to just one model, it
would be that of Boost, which executes a copy of the object you
pass it. It's a slight hassle in the case of joinable threads,
if you want to access the results in the thread object after the
join, but that's nothing that an extra layer of indirection
can't fix. (Back in the old days, it was widely believed that
there was no problem which couldn't be solved by an extra layer
of indirection:).) (What bothers me most about the Boost model
is that if you miss catching an exception somewhere, you end up
with a detached thread, when what you wanted was to terminate
and join.)
 
J

James Kanze

"Szabolcs Ferenczi" <[email protected]> wrote in message
Where does the current C++ standard say that the STL is
"thread-safe to a certain extent"???

And the implementations I use are completely thread safe, not
just to a certain extent. The document very clearly what is and
is not guaranteed (even if what they guarantee is somewhat
surprising in the case of g++, since it contradicts Posix).
 
J

James Kanze

On May 18, 12:43 pm, darren <[email protected]> wrote:
[...]
Try to avoid using singletons (if you refer to the
singleton pattern). It is not a good idea even in
non-MT programs. You can always avoid using singletons
by disciplined programming. In this case you do not need
singleton either.
He is right
Bullshit. (If you read any of Szabolcs' postings, you'll
quickly realize that he's never actually written any real code.)
You don't want to abuse them, but there are special cases where
they are the appropriate solution. In the case of detached
threads, in fact, some form of singleton is almost necessary for
a clean shutdown.
Calm down, my friend, and do not write "Bullshit".

I call a spade a spade. If you don't post bullshit, I won't
respond with "bullshit".
If you do not know about something, do not attack it just
because of your ignorance.

Look who's talking.
The singleton pattern is discouraged even by its creator.

Given that the pattern has been around for years, I doubt that
we even know who its creator is. The fact remains that it is
the best known solution for a small number of particular cases.
Just because it can be (and frequently is) misused doesn't mean
it shouldn't be used where appropriate. (There is, in fact, no
other way to ensure clean shutdown if you're using detached
threads.)
 
J

James Kanze

You seem to be interpreting the table correctly,

Note that that document doesn't specify which OS is being used,
or---in the case of Linux, which threading model. (Note that
some threading models do not allow multiple threads within a
single process to execute on different CPU's. That makes thread
creation very cheap, but sort of defeats the purpose of having
multiple CPU's.)

[...]
Of course, that depends heavily on the rest of the design.
Quite a few people try creating a new thread for every
incoming connection. This would almost certainly be disastrous
if you created a new process for every connection instead.

That really depends on what the protocol is doing. FTP and
telnet, at least in the implementations I use, spawn a separate
process for each connection.
OTOH, if you create some sort of thread/process pool, then you
only incur that 50x overhead a few times while your server
starts up. After that, you might incur some overhead from
inter- rather than intra- process communication, but that's
mostly a separate question.

Process pools are a lot more difficult to manage than thread
pools, because you do have to communicate with a running process
in order to use them. (Although... under Solaris, at least, you
can put conditions and mutexes in shared memory, and access them
from different processes. so the difference isn't that great.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top