Subj : Re: Thoughts about threads in C++ To : comp.programming.threads From : Jomu Date : Fri Apr 29 2005 07:16 am Maciej Sobczak wrote: > Hi, > > Jomu wrote: > > It seems you would like to trade "function" and "object" approachs for > > "syntactic sugar" approach. > > No. I'd like to trade one syntactic sugar for another. :) Ok :) > > > Nothing bad in that, except you'll need > > some kind of "handle" for your threads > > This is what I want to avoid - intentionally. > I'm not interested in handles - these expose implementation details, > even when they are wrapped into "objects". What I'm interested in is > that I want to do something in paraller to something else. Only that. Do not fail in preserving fragile programmer's minds! Do not expose them to API cruelties, even if that API is three object types and seven method calls in total :). Java tried to preserve poor programmers. They ended with "every object is mutex and also condvar". Learn from them. > Consider: > > threaded > { > // instructions 1. > } > other > { > // instructions 2. > } > > What I want to say by this is that instructions 1. and 2. should be > executed in paraller. That's all. I don't care whether there will be a > new physical thread created to do this. The implementation has to do You have cobegin/coend (Dijkstra, sixties) there. What you lack is "region" and "shared" or "LOCK" to get suite at least running. Maybe you can add "shared" as qualifier for object you need exclusive access control for. And some: lock (mySharedVar) { ... } It will "solve" mutex. rwlock can be solved in similar manner. lockr (mySharedRWVar) { } It can be done with two qualifiers and two keywords. There remains condvar to be introduced/solved. > what it has to do, whether this is: > a. creating a new physical thread and releasing it afterwards > b. reusing a thread that was created previously Done implicitly in most systems. > c. run everything explicitly in separate pipelines of the multicore CPU, > which actually does not require any OS-level threading at all It always needs some "OS-level", at least to manage OS resource sharing. > d. (whatever else) > > By explicitly creating threads and messing with their IDs (or handles) I > bind myself to a. or b., which at this level is irrelevant to me. When I do use threads, most of ID's are ignored. Like: EVAL Thread.Fork(...); When I need ID, I can get it there and use when I need it - to timeout process, to cancel it... Runtime knows them all and uses them to manage garbage collection. > What is relevant is the concurrency. I'd like the implementation and the > environment to pick the low-level scheme for me. Of course. That's why we do threads abstraction at programming language level at all. > > so you can cancel them, suspend > > them, whatever them by some id. > > Which is what I do not want to do on this level (see questions at the > end of the referenced article). I've read them. How do you plan to timeout or generally abort some stuck thread? > When I actually do want to do something that is outside of this scheme > (and it may happen from time to time), I can do it with "traditional" > approaches, which will usually boil down to APIs like pthreads. > Please note that if Boost.Threads gets into the C++ standard, it will be > in the same position - most of the time it will be enough for general > use but when it is not (have you seen cancel, suspend, whatever there?), I am not talking C++, I am talking threads and syntactic sugar :). > people will call low-level APIs directly. This is to be expected. If > that has to be the case, I see no purpose for IDs or objects. But you need objects for mutex and condvar? And, as C++ is all objecty and thingies, why don't thread objects? And when two (or three, with rwlock) basic elements are objects, why run from "thread is object"? > > Also, your scope rules seem clumsy at one fast reading so > > it's maybe best to keep "thread body is function/method body" and rely > > on established/accepted/understood scope rules. > > This is a valid point, which I understand. On the other hand, by > introducing concurrency into the language you may expect to stirr things > a little bit, especially in the context of lifetime rules. > What I described is essentially no different from the > established/accepted/understood approaches when you pass things by value > to the new thread, even if it then becomes a dangling pointer. ;) But why don't pass them as reference also? Isn't that what we do when introduce a thread - we share address space as it is, without strings and exceptions except:) for concurrency control. > > > Important thing to note, IMHO, is: pthreads approach is also "threads > > are objects". They are definitely object based, even in their simplest > > "C library" form. > > Of course. If you extrapolate this by saying that any object-based > wrapper around pthreads gives nothing but syntactic sugar, I will agree. > That's why I think that the existence of concurrency in the program has > to be acknowledged at the level of control statements, and not hidden > behind objects, functions (or even functors) and IDs. That's what Modula-3 does, with MUTEX. We did a scripting language with: thread ThisIsNotAProc() = begin ... end ThisIsNotAProc; which, when called like any procedure is called, spawns a thread. Locking is done as in Modula-3 with: lock mutexvar do ... end; With wait sigVar, mutexvar; and signal sigVar; we do synchronizing. That's about it, basically. If we do: id:=ThisIsNotAProc(); we can: alert id; or finish id; That's it. No API festivals. :) dd > > -- > Maciej Sobczak : http://www.msobczak.com/ > Programming : http://www.msobczak.com/prog/ .