What's the connection between objects and threads?

S

Szabolcs Ferenczi

Are you trying to say that you cannot use STL containers for
communications between threads?

What I am saying is that you cannot use it without any extra
synchronisation provided there are multiple producer and consumer
threads. That was my original warning what triggered your conditioned
reflex.

<quote>
Be aware that although STL is thread-safe to a certain extent, you
must wrap around the STL data structure to make a kind of a bounded
buffer out of it.
 I use std::deque, for example,
in my message queue, and it works perfectly.

That is your homework to show a solution where two competing threads
are consuming from a "completely thread safe" std::deque.

Yes, you talk big like the Bandar-log, that you can do that---but when
it comes to show it, you escape with same talk.

We are waiting for your report about your homework.

Best Regards,
Szabolcs
 
C

coal

To put it a little more abstractly: ensuring data integrity in a
multi-threaded application requires an application-level solution. A
library or language can provide tools to make this easier, but they
cannot solve the problem.

I agree with the gist of that, but think Kanze put it well enough.
I wouldn't describe an approach that makes deadlocks more likely than
other approaches as having a problem with data integrity. I'd say it
was a problem of application integrity.

Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
 
S

Szabolcs Ferenczi

Hmm...

I showed you one reason why its not a good idea to spawn threads from ctors.

You showed nothing else but that you can hack C++ even in sequential
mode so that the compiler cannot catch your misuse. That was it.
Congratulations.
I could show you some others, but I suspect that you already know them. See,
I think you know that starting threads from ctors is "generally" a bad idea,
and your just doing a little trolling for some reason. Oh well.

I taked about disciplined use. Of course, that is not for hackers like
you.

Hackers also do not know that there are computational models where
objects and processes are unified into active objects. And that
exactly means that the object starts its activity right after
initialising its internal state. So it is not at all new concept. Ok,
you and your friends cannot know that due to lack of education in
concurrent programming.

Best Regards,
Szabolcs
 
S

Szabolcs Ferenczi

You say:
Here is a very simple FIFO queue:

Who asked you to hack a FIFO queue here? Are you Kanze's pet or
servant? It was his homework.

Besides you better wait for your master's solution because according
to him, he is going to solve it just by the plain std::dequeue. He
clamed that he used to use it in his programs just like that because
it is "completely thread safe". The Bandar-log master will not use any
other mutex for it.

Be patient and wait for your master's solution, young friend.

Best Regards,
Szabolcs
 
S

Szabolcs Ferenczi

I am quite sure that James can create trivial code like that.

I doubt that. So far he proved the opposite. He just talks big.
Why do you think he is my master?

You do his job. You work for him. It is so simple.

Best Regards,
Szabolcs
 
J

James Kanze

What I am saying is that you cannot use it without any extra
synchronisation provided there are multiple producer and
consumer threads.

And?

The SGI implementation gives a contract concerning how you must
use them in a multi-threaded environment. You follow the
contract, and there should be no problems. You violate the
contract, and who knows. That's no different from anything
else.

In practice, of course, there's no sense in offering any other
contract, given the interface of the STL. Things like
operator[] and * on an iterator return references. So you can't
offer anything more than the basic contract that is present for
individual instances of the contained object. In the case of
the SGI implementation, this corresponds to the Posix contract.

And while I'm not saying that Posix is perfect, I would consider
its use of language "standard". And according to Posix, the SGI
contract is thread-safety.
That was my original warning what triggered your conditioned
reflex.

You didn't word it like that. If you had, I'd have agreed.

Let's be very clear: thread safety is a question of contract. A
component is thread safe *if* it specifies exactly what the
contract is in the presense of threads. We can argue the issue
a little, if the contract starts offering less guarantees that
the Posix, say (e.g. accessing two different objects requires
external synchronization), but there are limits. The STL
doesn't claim to provide synchronization; calling
deque<>::front() will *not* suspend your thread until there is
something in the queue. But this just seems so normal to me,
for a *container*, that I can't imagine anyone thinking
otherwise.

And for what its worth, the message queue I use between
processes is based on std::deque. And it's now being used in a
number of different applications, with no problems. Just as
obviously, there's some other code around it, to ensure
synchronization; this code does more than just protect accesses
to the queue, it suspends a thread if the queue is empty, etc.
(For the record, it uses both a pthread_cond_t and a
pthread_mutex_t.)
<quote>
Be aware that although STL is thread-safe to a certain extent, you
must wrap around the STL data structure to make a kind of a bounded
buffer out of it.
</quote>http://groups.google.com/group/comp.lang.c++/msg/4450c4f92d6e0211
That is your homework to show a solution where two competing
threads are consuming from a "completely thread safe"
std::deque.

For various reasons, the actual code contains a lot of
"irrelevant" additions (templates, etc.), but it's really just
the classical implementation of a message queue under Posix,
with std::deque serving as the queuing mechanism.
Yes, you talk big like the Bandar-log, that you can do
that---but when it comes to show it, you escape with same
talk.
We are waiting for your report about your homework.

You're not my teacher. Since it's a classical implementation (I
think there's a similar example in the Butenhof), it seems like
a waste of time to post it here. The only really original thing
in it is the fact that I use std::auto_ptr in the interface, not
so much to manage memory as to ensure that once a thread has
passed an object off to the queue, it cannot access it any more.
 
S

Szabolcs Ferenczi

Why do you need to start threads in ctors? That can be dangerous. However,
if your careful, it can be done. Here is a simple example:

<pseudo-code sketch>
______________________________________________________________
class thread_base {
  virtual void on_entry() = 0;

public:
  void start() { ... };
  void join() { ... };

};

class active_object : public thread_base {
public:
  active_object() {
    // construct
  }

private:
  void on_entry() {
    // running
  }

  virtual void on_object_state_shift() = 0;

};

template<typename T>
struct run {
  T m_object;
  run() { m_object.start(); }
  ~run() throw() { m_object.join(); }

};

class my_object : public active_object {
  void on_object_state_shift() {
    // whatever...
  }

};

int main() {
  {
    run<my_object> mobj;
  }
  return 0;

}

Great. It looks good.
-- or --

int main() {
  {
    my_object mobj;
    mobj.start();
    mobj.join();
  }
  return 0;}

______________________________________________________________

This works fairly well because the run<T> template has nothing to do with
any active object state. It only ensures that the object has been fully
constructed __before__ the thread which drives it has been created...

Any thoughts?

So far so good. I still have to check it out but this is something I
was looking for. If we replace the term `run' with `active' or
something of a more meaningful term, we are done.

I think this construction could be considered by the committee of C+
+0x as well.

Well done.

Best Regards,
Szabolcs
 
J

James Kanze

On May 21, 9:02 pm, "Chris Thomasson" <[email protected]> wrote:
Who asked you to hack a FIFO queue here? Are you Kanze's pet or
servant? It was his homework.

I'm sorry, but you are not my teacher, and you don't give me
homework. The work I do belongs to the people who pay me.
Technically, I'd need their authorization before I could post it
here. Practically, the code in question is small enough and
simple enough---and independent of our application domain---so I
doubt they'd care. But I'm certainly not going to post it just
because you want to play the teacher. (What is it they say:
those that can, do. Those that can't, teach. With my excuses
to the many competent teachers I've known.)
Besides you better wait for your master's solution

What's this business about "master"? What kind of social
relationships do you have, that people are masters and slaves?
 
J

James Kanze

I agree with the gist of that, but think Kanze put it well enough.

Maybe, but Pete said it a lot clearer, in a lot fewer words.
It's an application level problem, in the end, and all the
library, the language (or the OS, or anything else) can provide
are tools.
 
S

Szabolcs Ferenczi

I'm sorry, but you are not my teacher,

Right. You can be sorry about it, since if I were your teacher you
would have been properly educated in concurrent programming.
and you don't give me
homework.

I did. I just made use of your bad habit of talking big and caught
you.
 The work I do belongs to the people who pay me.

It is not a big deal. Just show how you do what you claimed to do.
Technically, I'd need their authorization before I could post it
here.

It is an escape. Any one of us could eaasily make a reduced version of
any interesting part of the code base so that no one could identify
the source. But the one who just talks big, cannot do that for some
strange reason.
 Practically, the code in question is small enough and
simple enough---and independent of our application domain---so I
doubt they'd care.

Then why don't you do it? Yes, it is a simple prolbem, you could type
it just like that. Of course, if you were not just a talking guy.
 But I'm certainly not going to post it just
because you want to play the teacher.

That is the escape root of the incapable. Just like Bandar-log.
Congratulations. You have presented the proof well enough.

Best Regards,
Szabolcs
 
K

kwikius

Right. You can be sorry about it, since if I were your teacher you
would have been properly educated in concurrent programming.

I'm really excited by everything you have said in this discussion and I
would really like to learm more.
It sounds like you are a University professor. I would love to take one of
your courses.

Where do you teach?

regards
Andy Little
 
R

Rolf Magnus

Szabolcs said:
I will not name any platform since I did not claim that "fork() is
very fast".

Well, it seems you wanted to imply something with your posting. Otherwise,
it's about as useful for this thread as a question like "what did you have
to eat today?"
Please ask the one who claimed it. Besides, you can guess the platform.

The platform I'm using is Linux. But I think it's not so uncommon for
Unix-like systems to have a very efficient fork() implementation.
I have concluded already that some of you have a well developed
conditioned reflex wich is so accute that you tend to address me even
if I did not claim anything.

Why did you write your posting then? Anyway, the answer to you question
is "yes", if that helps.
 
S

Szabolcs Ferenczi

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):
_________________________________________________________________
template<typename T>
struct active {
  class guard {
    T& m_object;

  public:
    guard(T& object) : m_object(object) {
      m_object.start();
    }

    ~guard() {
      m_object.join();
    }
  };

  T m_object;

  active() {
    m_object.start();
  }

  ~active() {
    m_object.join();
  }};

_________________________________________________________________

To create and start an object in one step you do:

{
  active<foo> _foo;

}

or you can separate the process and intervene in between the object
construction and activation like:

{
  foo _foo;
  [...];
  active<foo>::guard active_foo(_foo);

}

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.

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:

<quote>
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
Effects:
As if:
while (!pred())
wait(lock);
</quote>
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html

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.

Best Regards,
Szabolcs
 
K

kwikius

Chris Thomasson said:

Well. There was a kind of insane hope there that Szabolcs had some solid
body of work expressing his own practises in the field of concurrent
programming.

Threading is a solution to a hardware architecture problem. (Its easy for me
to say :)) C++ is very much locked in to the traditional architecture and
was designed around sequential, "step by step" programming. Threading seems
to work OK in practise, but also seems difficult to theorise about and thats
a big problem. (I may be wrong but as I understand it there is no formal
means to describe threads. think the term is a "calculus"?)

IOW threading in C++ is a very difficult problem, but there has been a it
seems a huge amount of work done so far in trying to get "something" ready
for the next version of the standard. And boy Oh boy whatever Is delivered,
you can bet its going to be way far from perfect.

Really AFAIK the best way forward for anyone who has serious issues with the
current work on threading in C++ is to write a paper and submit it to The
standards committee explaining their concerns and better providing well
thought out solutions. (Won't be me)

http://www.open-std.org/jtc1/sc22/wg21/

Bear in mind though that is I think quite late in the day to have much
impact.

Anyway for myself I find this whole hardware architecture issue
interesting. Its way O.T. but I love this talk:


(Apologies I already put this link in another thread, but I Love this!)

I have already started trying to figure out how to tackle writing software
on a beast such as described, what your primitives would be. Anyway C++
seems to be as good a language as any to write my sim, but no threads in
sight in the implementation!

regards
Andy Little
 
S

Szabolcs Ferenczi

* kwikius:


I think there must be by now.  E.g. Hoare introduced a lot of notation and ways
to reason formally about these things in "Communicating sequential processes",
many tens of years ago.  But he didn't there address differences between threads
and heavy-weight processes (his processes appear more like threads, sharing
memory, than what we currently mean by "process" in the context of OS).

Be aware that CSP (Communicating Sequential Processes) is not a shared
memory based model. Processes in CSP communicate by messages and
messages are handled with adapted form of Guarded Commands. One unit
in CSP is a sequential program, hence the name. Besides, there is a
software realisation of CSP called OCCAM and there is a hardware
realisation of it called the Transputer.

The model that works with shared memory as well is Distributed
Processes. A Distributed Process is a combination of a monitor and a
process but Distributed Processes are communicating with each other
with remote procedure call-like mechanism. DP also applies Guarded
Commands. Hence one unit in DP is a combination of a shared object and
process.

We have just taken a step towards DP with unifying objects and
processes
http://groups.google.com/group/comp.lang.c++/msg/20c14991f9e88482

Also note that the term process was introduced for the abstract
concept of a thread of computation (or virtual processor) irrespective
of whether it is a heavy-weight process with its own address space and
resources or whether it is a light-weight one with its shared address
space and resources.

Best Regards,
Szabolcs
 
K

kwikius

Alf P. Steinbach said:
* kwikius:

I think there must be by now. E.g. Hoare introduced a lot of notation and
ways to reason formally about these things in "Communicating sequential
processes", many tens of years ago. But he didn't there address
differences between threads and heavy-weight processes (his processes
appear more like threads, sharing memory, than what we currently mean by
"process" in the context of OS).

Well I managed to track what I think is the latest version down:

http://www.usingcsp.com/cspbook.pdf

(I avoided most of the technical stuff , but the pictures were nice :) )

One passage was interesting.

P 209 section 7.2

"... In its full generality, multithreading is an incredibly complex and
errorprone
technique, not to be recommended in any but the smallest programs.
In excuse, we may plead that it was invented before the days of structured
programming, when even FORTRAN was still considered to be a high-level
programming
language!"

I think I am quoting somewhat out of context there and bear in mind he's
presumably a mathematician at heart, but essentially I think there are 2
schools, the message passing school and the shared memory school. As I
understand it C++0x is getting the shared memory school basically because
its performance potential is much better for C++, but OTOH doesnt lend
itself very well to formal analysis. And presumably you can build message
passing more easily anyway as its at a higher level.

regards
Andy Little
 
S

Szabolcs Ferenczi

Well I managed to track what I think is the latest version down:

http://www.usingcsp.com/cspbook.pdf

That is a bit different already from the original proposal. The
original proposal introduced seven primitives to build on.
(Communicating Sequential Processes, C.A.R. Hoare. Communications of
the ACM 21(8):666-677, August 1978)
[...]
 One passage was interesting.

P 209 section 7.2

"... In its full generality, multithreading is an incredibly complex and
errorprone
technique, not to be recommended in any but the smallest programs.
In excuse, we may plead that it was invented before the days of structured
programming, when even FORTRAN was still considered to be a high-level
programming
language!"

I think I am quoting somewhat out of context there [...]

Although you opened the book at the historical overview, this is our
topic here. He talks about the Unix-like fork-join style of processes.
That is what he calls multithreading. He does not mean the multi-
threading of today. Anyway, the criticism applies to nowadays
threading also: The process starting is unstructured.

Besides, that is what we tried to fix here in this discussion thread
in case of object-oriented programs in C++.

If you read further, you can find that Hoare considers structured
parallelism. That is what can be achieved with the unified active
objects we worked out here. See one of my first messages to this
discussion thread:

<quote>
There are programming models where there are objects which are active
entities. As I earlier mentioned one early proposal of this kind is
the Distributed Processes programming concept. ...

That means that you can use configurator blocks in your program where
you declare so-called thread objects and shared objects together.

{
Buffer b;
Producer p(b);
Consumer c(b);
}

The block realises a parallel block or fork-join block as they call
it
in a trendy terminology.
</quote>
http://groups.google.com/group/comp.lang.c++/msg/250fdce805e9f407

If you read even further in that book, you will find the Conditional
Critical Region language concept too what I am suggesting to adapt
into C++0x.

Best Regards,
Szabolcs
 
J

Jerry Coffin

[ ... ]
"... In its full generality, multithreading is an incredibly complex and
errorprone technique, not to be recommended in any but the smallest programs.

I think we can stop right there. For the moment, think of multithreading
only in a cooperatively multitasked, uniprocessor environment. This is
probably the most restricted case of multithreading, but even so it's
already essentially equivalent to unrestricted flow control (i.e.
spawning a thread is virtually equivalent to a goto in disguise).

Hoare was one of the early proponents of structured programming. As
such, I suspect he saw multhreading "in its full generality" as a
possible way of re-introducing the same old problems of unstructured
programming in a new guise.

I think his argument is primarily for creating a set of 'flow-control'
constructs for multithreading that give a structured view of its
capabilities, much like more conventional flow control constructs give a
structured view of single-threaded flow control capabilities.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top