www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Sharing in D

reply Walter Bright <newshound1 digitalmars.com> writes:
http://www.reddit.com/comments/6u7k0/sharing_in_d/
Jul 30 2008
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
WANT. It would be very useful for certain applications. However, I'm worried that this may perhaps add even more complexity to an already stretched type system. How about making the less safe alternative (shared/unchecked) the default (so current programs keep working the way they already do) and people who want the additional compelxity and overhead use unshared explicitly (just as const/invariant is not the default and people need to explicitly say that).
Jul 30 2008
parent reply bearophile <bearophileHUGS lycos.com> writes:
Bartosz Milewski:
 This requires that all objects, by default, be thread local. For instance, if
you declare a global object and initialize it in one thread, another thread
will see a different version of this object.<
This requires to be careful using global variables, because you may need lot of memory. On the other hand, each L1 cache can keep such objects safely, with little need of copying such data to other L1 caches. Robert Fraser:
 However, I'm worried that this may perhaps add even more complexity
 to an already stretched type system.
If the type system is able to manage the transitive immutability, then it can manage this too, I think. The things that are going to stress the type system of D are different ones, I think; for example see the thread about nested templates, where the best solution proposed was to use an union to punch a hole in it. Bye, bearophile
Jul 31 2008
next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
bearophile Wrote:
 Robert Fraser:
 However, I'm worried that this may perhaps add even more complexity
 to an already stretched type system.
If the type system is able to manage the transitive immutability, then it can manage this too, I think. The things that are going to stress the type system of D are different ones, I think; for example see the thread about nested templates, where the best solution proposed was to use an union to punch a hole in it.
I was talking UX wise. I don't want to have to think whether my variable is a shared(atomic(const(int)*)[]).
Jul 31 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 If the type system is able to manage the transitive immutability,
 then it can manage this too, I think.
I've already worked out the implementation issues of transitivity, so I can easily leverage that code for the sharing transitivity.
Jul 31 2008
prev sibling next sibling parent JAnderson <ask me.com> writes:
Walter Bright wrote:
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
I like this proposal. Maybe the shared option could be in the typical bracket notation that D is so fond off: shared { Object X; //Shared object class Foo() {} //Shared class for any object that uses this / Shared members class Bar() {} } That way the few people that are passing non-shared objects around can simply put everything into a shared block, simplifying migration. -Joel
Jul 30 2008
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data. I would hazard to guess that adopting this would cause a larger rift than const. Second, the fact that you can't implicitly cast shared to unshared and vice versa. It's going to make communication between both 'worlds' very error prone, as you will be required to cast for any call from one to the other. People will do this just to get their code to work, without thinking about the consequences. Even those that do think about the consequences, can't have the compiler statically check the cast in either direction, so once you cast, you lose all the benefit. I'd have to see solutions to these before I'd think it was a good idea. Or else examples of how to avoid these problems. -Steve
Jul 30 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data.
Nearly all global data is assumed to be and treated as if it were unshared. So making unshared the default is the right solution. And frankly, if you're using a lot of global variables, you might want to reevaluate what you're doing. Lots of global variables is the 80's style of programming :-)
 I would hazard to guess that adopting this would 
 cause a larger rift than const.
Perhaps. But the alternative is the current wild west approach to multithreaded programming. With the proliferation of multicore computers, the era where this is acceptable is coming to an end.
 Second, the fact that you can't implicitly cast shared to unshared and vice 
 versa.  It's going to make communication between both 'worlds' very error 
 prone, as you will be required to cast for any call from one to the other.
I think the reverse is true. Moving data between those worlds is dangerous and needs to be carefully vetted, so requiring an explicit cast will reduce the chance of this happening unintentionally.
 People will do this just to get their code to work, without thinking about 
 the consequences.
True, but having it happen implicitly is even worse, because there's no indication that it is happening.
 Even those that do think about the consequences, can't 
 have the compiler statically check the cast in either direction, so once you 
 cast, you lose all the benefit.
But still, you're far better off than the current wild west approach where everything is implicitly shared with no protection whatsoever. The popular double checked locking bug will be impossible to code in D without stuffing in explicit casts. The casts will be a red flag that the programmer is making a mistake.
 I'd have to see solutions to these before I'd think it was a good idea.  Or 
 else examples of how to avoid these problems.
Jul 30 2008
next sibling parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 Steven Schveighoffer wrote:
 I would hazard to guess that adopting this would cause a larger rift
 than const.
He's probably right.
 
 Perhaps. But the alternative is the current wild west approach to
 multithreaded programming. With the proliferation of multicore
 computers, the era where this is acceptable is coming to an end.
 
Since when is it the language's job to tell us what's acceptable and what's not?
 But still, you're far better off than the current wild west approach
 where everything is implicitly shared with no protection whatsoever. The
 popular double checked locking bug will be impossible to code in D
 without stuffing in explicit casts. The casts will be a red flag that
 the programmer is making a mistake.
 
The double checked locking "bug" is only a bug on certain architectures, none of which D is supported on. What's the point here again? --downs
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 Walter Bright wrote:
 Steven Schveighoffer wrote:
 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
 Perhaps. But the alternative is the current wild west approach to 
 multithreaded programming. With the proliferation of multicore 
 computers, the era where this is acceptable is coming to an end.
Since when is it the language's job to tell us what's acceptable and what's not?
I meant that programmers will no longer find the language acceptable if it doesn't offer better support.
 But still, you're far better off than the current wild west
 approach where everything is implicitly shared with no protection
 whatsoever. The popular double checked locking bug will be
 impossible to code in D without stuffing in explicit casts. The
 casts will be a red flag that the programmer is making a mistake.
The double checked locking "bug" is only a bug on certain architectures, none of which D is supported on.
D is not only meant to be more than an x86 only language, the x86 family steadily moves towards the relaxed sequential consistency model. The threading model supported by Java and the upcoming C++0x release are both based on the relaxed model, that is clearly where the industry expects things to go, and I see no reason to believe otherwise.
Jul 31 2008
next sibling parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 downs wrote:
 Walter Bright wrote:
 Steven Schveighoffer wrote:
 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
 Perhaps. But the alternative is the current wild west approach to
 multithreaded programming. With the proliferation of multicore
 computers, the era where this is acceptable is coming to an end.
Since when is it the language's job to tell us what's acceptable and what's not?
I meant that programmers will no longer find the language acceptable if it doesn't offer better support.
 But still, you're far better off than the current wild west
 approach where everything is implicitly shared with no protection
 whatsoever. The popular double checked locking bug will be
 impossible to code in D without stuffing in explicit casts. The
 casts will be a red flag that the programmer is making a mistake.
The double checked locking "bug" is only a bug on certain architectures, none of which D is supported on.
D is not only meant to be more than an x86 only language, the x86 family steadily moves towards the relaxed sequential consistency model. The threading model supported by Java and the upcoming C++0x release are both based on the relaxed model, that is clearly where the industry expects things to go, and I see no reason to believe otherwise.
Point taken, taken and taken. If this can be done well, I believe it may become a significant advantage for the language. IMHO, however, most global variables are intended to be instantiated only once, not once per thread. Because of this, the success of this model hinges on how easy an object can be transferred between threads. Some sort of language enforced blocking, maybe? I.e. if you mark an object as unique, as in, "unique Class foo", it is implicitly shared, but *treated as if it were nonshared*, as threads need to acquire a sync lock before accessing the object, and references to the object or its members cannot leave the sync block. Delegates would be a special case: they can leave the sync lock, as long as any "this" access inside them is itself synchronized. --downs
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 IMHO, however, most global variables are intended to be instantiated
 only once, not once per thread. Because of this, the success of this
 model hinges on how easy an object can be transferred between
 threads. Some sort of language enforced blocking, maybe?
The idea is to no longer allow unsynchronized uncontrolled sharing of data between threads as the *default* behavior. If you want to do it, you'll have to do it *intentionally*. Note that invariant data will be implicitly shared because it does not need synchronization or fencing.
Jul 31 2008
parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 downs wrote:
 IMHO, however, most global variables are intended to be instantiated
 only once, not once per thread. Because of this, the success of this
 model hinges on how easy an object can be transferred between
 threads. Some sort of language enforced blocking, maybe?
The idea is to no longer allow unsynchronized uncontrolled sharing of data between threads as the *default* behavior. If you want to do it, you'll have to do it *intentionally*.
Yeah, but I'd like a way to do it that doesn't leave me entirely on my own, considering that it's imho a common use-case.
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 Walter Bright wrote:
 downs wrote:
 IMHO, however, most global variables are intended to be
 instantiated only once, not once per thread. Because of this, the
 success of this model hinges on how easy an object can be
 transferred between threads. Some sort of language enforced
 blocking, maybe?
The idea is to no longer allow unsynchronized uncontrolled sharing of data between threads as the *default* behavior. If you want to do it, you'll have to do it *intentionally*.
Yeah, but I'd like a way to do it that doesn't leave me entirely on my own, considering that it's imho a common use-case.
I don't understand what you're asking for.
Jul 31 2008
parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 downs wrote:
 Walter Bright wrote:
 downs wrote:
 IMHO, however, most global variables are intended to be
 instantiated only once, not once per thread. Because of this, the
 success of this model hinges on how easy an object can be
 transferred between threads. Some sort of language enforced
 blocking, maybe?
The idea is to no longer allow unsynchronized uncontrolled sharing of data between threads as the *default* behavior. If you want to do it, you'll have to do it *intentionally*.
Yeah, but I'd like a way to do it that doesn't leave me entirely on my own, considering that it's imho a common use-case.
I don't understand what you're asking for.
Sorry. I am looking for a safe way to transfer ownership of a single object between threads. Like, for instance, a "unique Object foo" would behave like a shared Object, but the compiler would treat it like a nonshared object for purposes of optimization, and all accesses from the outside would be implicitly synchronized. This could be used for objects that really are only supposed to exist once, but still used in a multithreaded way. Hope that clears things up.
Aug 01 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.
 
 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.
 
 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.
 
 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Aug 01 2008
parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.

 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.

 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.

 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Okay. In the current system, every object "belongs" to every thread equally - synchronization blocks are used to prevent interference. In the new system, this behavior, if I understand correctly, is equivalent to "shared". The default, non-shared, would be objects that belong, permanently, to exactly one thread - the one that created them, to the extent that accessing them from another thread would constitute a compiler failure. What I am looking for, then, is to somehow temporarily, or permanently, change the thread that a specific instance belongs to, transfer ownership to another thread, so to speak, in an atomic manner - so that at no time more than one thread possesses ownership of the object - thus gaining, basically, the guaranteed thread-safety of a non-shared object with the convenience of a shared object. So it's basically a form of forced "synchronized" blocks - a thread that would try to access such an "unique" object, would first have to acquire ownership of it, to prevent threading issues - an action similar to the current "synchronized(this)". In fact, every access to an unique object would come down to an implicit "synchronized(obj)", which would allow us to treat the object as if it _were_ thread-local for the purpose of that access, because even though it isn't, no other thread could interfere with it. Hope that clears things up :/
Aug 01 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from downs (default_357-line yahoo.de)'s article
 Walter Bright wrote:
 downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.

 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.

 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.

 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Okay. In the current system, every object "belongs" to every thread equally -
synchronization blocks are used to prevent interference.
 In the new system, this behavior, if I understand correctly, is equivalent to
"shared".
 The default, non-shared, would be objects that belong, permanently, to exactly
one thread - the one that created them, to the extent that accessing them from another thread would constitute a compiler failure.
 What I am looking for, then, is to somehow temporarily, or permanently, change
the thread that a specific instance belongs to, transfer ownership to another thread, so to speak, in an atomic manner - so that at no time more than one thread possesses ownership of the object - thus gaining, basically, the guaranteed thread-safety of a non-shared object with the convenience of a shared object. We've discussed creating per-thread GCs in Tango to eliminate the problem of "stop the world" collections. Transferral of ownership is complicated with such a model, however, if the object being transferred represents a resource. Everything else you can just .dup (ie. perform a deep copy), but obviously not singletons. I'd be inclined to say that this is a limitation you'll just have to deal with when designing your program. Make one thread the "owner" of the object and have other threads interact with it basically via messaging. This idea of per-thread GCs dovetails perfectly with 'shared' as well, since there's no way in D 1.0 to flag the creation of static data. In D 2.0 however, it sounds like all such data either must be labeled 'shared' or can be made thread-local as well. Totally awesome. Of course, that still means that memory backing shared data will leak in the absence of a GC, so either this would have to be stated and the user would have to deal with it, or there would still need to be a global "stop the world" GC specifically for the shared data. In the latter case, I'd probably default the GC to disabled so the user would either collect manually or enable it if he doesn't care about an occasional "stop the world" collection. Sean
Aug 01 2008
next sibling parent JAnderson <ask me.com> writes:
Sean Kelly wrote:
 == Quote from downs (default_357-line yahoo.de)'s article
 Walter Bright wrote:
 downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.

 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.

 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.

 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Okay. In the current system, every object "belongs" to every thread equally -
synchronization blocks are used to prevent interference.
 In the new system, this behavior, if I understand correctly, is equivalent to
"shared".
 The default, non-shared, would be objects that belong, permanently, to exactly
one thread - the one that created them, to the extent that accessing them from another thread would constitute a compiler failure.
 What I am looking for, then, is to somehow temporarily, or permanently, change
the thread that a specific instance belongs to, transfer ownership to another thread, so to speak, in an atomic manner - so that at no time more than one thread possesses ownership of the object - thus gaining, basically, the guaranteed thread-safety of a non-shared object with the convenience of a shared object. We've discussed creating per-thread GCs in Tango to eliminate the problem of "stop the world" collections. Transferral of ownership is complicated with such a model, however, if the object being transferred represents a resource. Everything else you can just .dup (ie. perform a deep copy), but obviously not singletons. I'd be inclined to say that this is a limitation you'll just have to deal with when designing your program. Make one thread the "owner" of the object and have other threads interact with it basically via messaging. This idea of per-thread GCs dovetails perfectly with 'shared' as well, since there's no way in D 1.0 to flag the creation of static data. In D 2.0 however, it sounds like all such data either must be labeled 'shared' or can be made thread-local as well. Totally awesome. Of course, that still means that memory backing shared data will leak in the absence of a GC, so either this would have to be stated and the user would have to deal with it, or there would still need to be a global "stop the world" GC specifically for the shared data. In the latter case, I'd probably default the GC to disabled so the user would either collect manually or enable it if he doesn't care about an occasional "stop the world" collection. Sean
Some good points. One thing that will likely happen with shared GC is that there will be relativity a very small amount of shared memory needed. Therefore GC collection on the shared memory might be fast enough for many people. If there's a lot of memory being shared its a sign that something might be wrong. That's because a huge amount of shared memory means that the benefit of multi-threading will seriously be diminished. Also maybe "shared" could eventually use a different kinda GC which is more optimal for shared memory. If there was a way to say which threads had read/write (or both) access to different shared memories then not all threads would need to be stopped. -Joel
Aug 02 2008
prev sibling parent reply Don <nospam nospam.com.au> writes:
Sean Kelly wrote:
 == Quote from downs (default_357-line yahoo.de)'s article
 Walter Bright wrote:
 downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.

 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.

 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.

 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Okay. In the current system, every object "belongs" to every thread equally -
synchronization blocks are used to prevent interference.
 In the new system, this behavior, if I understand correctly, is equivalent to
"shared".
 The default, non-shared, would be objects that belong, permanently, to exactly
one thread - the one that created them, to the extent that accessing them from another thread would constitute a compiler failure.
 What I am looking for, then, is to somehow temporarily, or permanently, change
the thread that a specific instance belongs to, transfer ownership to another thread, so to speak, in an atomic manner - so that at no time more than one thread possesses ownership of the object - thus gaining, basically, the guaranteed thread-safety of a non-shared object with the convenience of a shared object. We've discussed creating per-thread GCs in Tango to eliminate the problem of "stop the world" collections. Transferral of ownership is complicated with such a model, however, if the object being transferred represents a resource. Everything else you can just .dup (ie. perform a deep copy), but obviously not singletons. I'd be inclined to say that this is a limitation you'll just have to deal with when designing your program. Make one thread the "owner" of the object and have other threads interact with it basically via messaging. This idea of per-thread GCs dovetails perfectly with 'shared' as well, since there's no way in D 1.0 to flag the creation of static data. In D 2.0 however, it sounds like all such data either must be labeled 'shared' or can be made thread-local as well.
Would this be an end to 'static' variables?
Aug 14 2008
parent Sean Kelly <sean invisibleduck.org> writes:
Don wrote:
 Sean Kelly wrote:
 == Quote from downs (default_357-line yahoo.de)'s article
 Walter Bright wrote:
 downs wrote:
 I am looking for a safe way to transfer ownership of a single object
 between threads.

 Like, for instance, a "unique Object foo" would behave like a shared
 Object, but the compiler would treat it like a nonshared object for
 purposes of optimization, and all accesses from the outside would be
 implicitly synchronized.

 This could be used for objects that really are only supposed to exist
 once, but still used in a multithreaded way.

 Hope that clears things up.
Sorry, I still have no idea what you're asking for.
Okay. In the current system, every object "belongs" to every thread equally -
synchronization blocks are used to prevent interference.
 In the new system, this behavior, if I understand correctly, is 
 equivalent to
"shared".
 The default, non-shared, would be objects that belong, permanently, 
 to exactly
one thread - the one that created them, to the extent that accessing them from another thread would constitute a compiler failure.
 What I am looking for, then, is to somehow temporarily, or 
 permanently, change
the thread that a specific instance belongs to, transfer ownership to another thread, so to speak, in an atomic manner - so that at no time more than one thread possesses ownership of the object - thus gaining, basically, the guaranteed thread-safety of a non-shared object with the convenience of a shared object. We've discussed creating per-thread GCs in Tango to eliminate the problem of "stop the world" collections. Transferral of ownership is complicated with such a model, however, if the object being transferred represents a resource. Everything else you can just .dup (ie. perform a deep copy), but obviously not singletons. I'd be inclined to say that this is a limitation you'll just have to deal with when designing your program. Make one thread the "owner" of the object and have other threads interact with it basically via messaging. This idea of per-thread GCs dovetails perfectly with 'shared' as well, since there's no way in D 1.0 to flag the creation of static data. In D 2.0 however, it sounds like all such data either must be labeled 'shared' or can be made thread-local as well.
Would this be an end to 'static' variables?
I think that's the only feasible option for D1, which is why I'm hesitant to pursue per-thread GCs. It's a restriction that would have no language support but rather rely on convention to prevent crashes. For D2 I think it may be possible to rely on the transitivity of 'shared' and to use this type qualifier to allocate from a central "stop the world" GC. The tricky thing here is that local data would have to be copied if it were to be referenced only from the shared area, similar to an .idup I suppose. Sean
Aug 14 2008
prev sibling next sibling parent reply Helmut Leitner <leitner wikiservice.at> writes:
Walter Bright wrote:
 downs wrote:
 
 Walter Bright wrote:

 Steven Schveighoffer wrote:

 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
Perhaps this has already been discussed, but there seems another upcoming arms race between probably - NVIDIA/CUDA, currently available 200+ cores available at $500 - Intel multicore, probably available in 12+ months competing in - scientific number-crunching - life video encoding (hot topic) I think it would be a BIG marketing effect for D, if it could support the NVIDIA/CUDA system. Probably it would even get payed by NVIDIA. Helmut
Jul 31 2008
next sibling parent reply "Koroskin Denis" <2korden gmail.com> writes:
On Thu, 31 Jul 2008 19:15:03 +0400, Helmut Leitner  
<leitner wikiservice.at> wrote:

 Walter Bright wrote:
 downs wrote:

 Walter Bright wrote:

 Steven Schveighoffer wrote:

 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
Perhaps this has already been discussed, but there seems another upcoming arms race between probably - NVIDIA/CUDA, currently available 200+ cores available at $500 - Intel multicore, probably available in 12+ months competing in - scientific number-crunching - life video encoding (hot topic) I think it would be a BIG marketing effect for D, if it could support the NVIDIA/CUDA system. Probably it would even get payed by NVIDIA. Helmut
Other system to take into an account is Playstation 3. It has 7 cores, it runs Linux (YellowDog/Ubuntu/Gentoo...), it is cheap, it is available to everyone. The PS3's hardware has also been used to build supercomputers for high-performance computing. IIRC, it used to have the best cost/GFLOPS ratio some time ago. PS3 uses a GCC compiler which is freely available (I love GPL for that reason) so a GDC is a matter of time (and some effort). BTW, gdc is already ported to Playstation Portable. As a result, we could use a PS3 as a basis for an upcoming cuncurrent programming support in D. I just don't see any other *real* possibilities to get 4 or more cores for a low price.
Jul 31 2008
parent reply Helmut Leitner <leitner wikiservice.at> writes:
Koroskin Denis wrote:
 As a result, we could use a PS3 as a basis for an upcoming cuncurrent  
 programming support in D.
 I just don't see any other *real* possibilities to get 4 or more cores 
 for  a low price.
All NVIDIA graphics boards from 8400 up are usable via the CUDA interface. The newest GT200 chip that is build into the GTX-280 boards (GTX-260 has a just a lower core count) contains 240 cores. There is a number-crunching-only version of these graphics boards, called TESLA. The hi-end-boards promise to reach 1 TFLOP (single precision) and about 0.1 TFLOP (double precision). This is existing technology that is in the market.
Jul 31 2008
parent bearophile <bearophileHUGS lycos.com> writes:
Helmut Leitner:
 This is existing technology that is in the market.
And it's working fast as hell already, I have tried CUDA some on my GPU :-) There's an impressive demo named Particles: http://www.youtube.com/watch?v=U5eJ8RdR68I http://www.youtube.com/watch?v=RqduA7myZok It works like this on a card that costs about 70-80 euro, and it's amazing. Bye, bearophile
Jul 31 2008
prev sibling parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Helmut Leitner wrote:
 Walter Bright wrote:
 downs wrote:

 Walter Bright wrote:

 Steven Schveighoffer wrote:

 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
Perhaps this has already been discussed, but there seems another upcoming arms race between probably - NVIDIA/CUDA, currently available 200+ cores available at $500 - Intel multicore, probably available in 12+ months competing in - scientific number-crunching - life video encoding (hot topic) I think it would be a BIG marketing effect for D, if it could support the NVIDIA/CUDA system. Probably it would even get payed by NVIDIA. Helmut
This is a library realm topic, given the ability to mixin optimal code per the BLADE-esque technique.
Jul 31 2008
parent Kyle Furlong <kylefurlong gmail.com> writes:
Kyle Furlong wrote:
 Helmut Leitner wrote:
 Walter Bright wrote:
 downs wrote:

 Walter Bright wrote:

 Steven Schveighoffer wrote:

 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics. I suggested to Andrei and Bartosz just the other day that I don't expect the value in this model will be readily apparent. I'm pretty sure it won't be, as the issues are hard to understand. But the issues being hard to understand is exactly why this model is needed. There are surely several articles, papers, and tutorials in this :-)
Perhaps this has already been discussed, but there seems another upcoming arms race between probably - NVIDIA/CUDA, currently available 200+ cores available at $500 - Intel multicore, probably available in 12+ months competing in - scientific number-crunching - life video encoding (hot topic) I think it would be a BIG marketing effect for D, if it could support the NVIDIA/CUDA system. Probably it would even get payed by NVIDIA. Helmut
This is a library realm topic, given the ability to mixin optimal code per the BLADE-esque technique.
I spoke too soon, this would require asm support for those processors.
Jul 31 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 downs wrote:
 Walter Bright wrote:
 Steven Schveighoffer wrote:
 I would hazard to guess that adopting this would cause a larger
 rift than const.
He's probably right.
A couple years ago, I was in a room with 30 of the top C++ programmers in the country. The topic was a 2 day conference on how to support multithreading in C++. It soon became clear that only two people in the room understood the issues (and I wasn't one of them). I think I understand the issues now, but it has taken a long time and repeatedly reading the papers about it. It is not simple, and it's about as intuitive as quantum mechanics.
In my opinion, the easiest way to describe the hardware side of things is simply to say that the CPU does the exact same thing as the optimizer in the compiler, only it does this dynamically as the code is executing. The rest just involves ideas for how to constrain CPU and compiler optimizations so the app behaves as expected when concurrency is involved. In your defense, "volatile" is a perfectly suitable minimum for D, so you did get the gist of the issue, even at the outset. The catch is that, while "volatile" controls the compiler, you still need to control the CPU, so inline ASM is required as well. Fortunately, D has that :-) So please give yourself a bit more credit here. D1 works perfectly well for concurrent programming. It just support this is a sufficiently non-obvious way that only people who understand the issues involved are likely to realize it. But as most of this stuff should really be in a library anyway, I don't see a problem with things as they are. Finding a way for the average user to do safe concurrent programming is an entirely different issue in my opinion, and has only really been "solved," in my opinion, in the functional programming realm. And that's by eliminating data sharing--the bane of imperative languages everywhere.
 Perhaps. But the alternative is the current wild west approach to
 multithreaded programming. With the proliferation of multicore
 computers, the era where this is acceptable is coming to an end.
Since when is it the language's job to tell us what's acceptable and what's not?
I meant that programmers will no longer find the language acceptable if it doesn't offer better support.
I disagree. D is a systems language first and foremost. Much of the rest can be done in library code. That isn't to say that I wouldn't like improved multiprogramming support in the language for the things that are awkward to do in library code (a thread-local storage class, for example), but trying to prevent the user from shooting himself in the foot is unnecessary. Particularly if doing so incurs a runtime cost that is not avoidable.
 But still, you're far better off than the current wild west
 approach where everything is implicitly shared with no protection
 whatsoever. The popular double checked locking bug will be
 impossible to code in D without stuffing in explicit casts. The
 casts will be a red flag that the programmer is making a mistake.
The double checked locking "bug" is only a bug on certain architectures, none of which D is supported on.
D is not only meant to be more than an x86 only language, the x86 family steadily moves towards the relaxed sequential consistency model. The threading model supported by Java and the upcoming C++0x release are both based on the relaxed model, that is clearly where the industry expects things to go, and I see no reason to believe otherwise.
There was some talk in the C++0x memory model discussion that Intel was actually planning on providing equivalent or stronger guarantees for future processors rather than weaker ones. I'll admit to having been very surprised at the time, but apparently they feel that they can do so and still provide the performance people expect. I guess the resounding failure of the Itanic forced them to rethink what was required for a successful new processor design. If I remember correctly, it was Paul McKenney that brought this up if you feel like searching the archives. Sean
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 In my opinion, the easiest way to describe the hardware side of things is
 simply to say that the CPU does the exact same thing as the optimizer in
 the compiler, only it does this dynamically as the code is executing.  The
 rest just involves ideas for how to constrain CPU and compiler optimizations
 so the app behaves as expected when concurrency is involved.  In your defense,
 "volatile" is a perfectly suitable minimum for D, so you did get the gist of
 the issue, even at the outset.  The catch is that, while "volatile" controls
 the compiler, you still need to control the CPU, so inline ASM is required
 as well.  Fortunately, D has that :-)  So please give yourself a bit more
 credit here.  D1 works perfectly well for concurrent programming.  It just
 support this is a sufficiently non-obvious way that only people who
 understand the issues involved are likely to realize it.  But as most of
 this stuff should really be in a library anyway, I don't see a problem
 with things as they are.
Java has synchronization and volatile, and it isn't good enough.
 Finding a way for the average user to do safe concurrent programming is an
 entirely different issue in my opinion, and has only really been "solved," in
 my opinion, in the functional programming realm.  And that's by eliminating
 data sharing--the bane of imperative languages everywhere.
D will eliminate implicit data sharing. To share data, you'll have to mark it as shared, and with the marking will come extra help in fences and synchronization. I've looked at the two classic multithreaded problems - double checked locking, and sequential consistency between threads. This model prevents both of them from happening.
 I disagree.  D is a systems language first and foremost.  Much of the
 rest can be done in library code.  That isn't to say that I wouldn't
 like improved multiprogramming support in the language for the things
 that are awkward to do in library code (a thread-local storage class,
 for example), but trying to prevent the user from shooting himself in
 the foot is unnecessary.
 Particularly if doing so incurs a runtime
 cost that is not avoidable.
It is avoidable if you're willing to insert a cast. Putting in the cast says "I know how to handle the wild west, let me do it." The cast has zero runtime cost.
 There was some talk in the C++0x memory model discussion that Intel
 was actually planning on providing equivalent or stronger guarantees
 for future processors rather than weaker ones.  I'll admit to having
 been very surprised at the time, but apparently they feel that they
 can do so and still provide the performance people expect.  I guess
 the resounding failure of the Itanic forced them to rethink what was
 required for a successful new processor design.  If I remember
 correctly, it was Paul McKenney that brought this up if you feel like
 searching the archives.
Intel may be reacting to the disastrous problems conventional languages have with this. If it is solved (and I think we have a credible solution), Intel may change their direction.
Jul 31 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 In my opinion, the easiest way to describe the hardware side of things is
 simply to say that the CPU does the exact same thing as the optimizer in
 the compiler, only it does this dynamically as the code is executing.  The
 rest just involves ideas for how to constrain CPU and compiler optimizations
 so the app behaves as expected when concurrency is involved.  In your defense,
 "volatile" is a perfectly suitable minimum for D, so you did get the gist of
 the issue, even at the outset.  The catch is that, while "volatile" controls
 the compiler, you still need to control the CPU, so inline ASM is required
 as well.  Fortunately, D has that :-)  So please give yourself a bit more
 credit here.  D1 works perfectly well for concurrent programming.  It just
 support this is a sufficiently non-obvious way that only people who
 understand the issues involved are likely to realize it.  But as most of
 this stuff should really be in a library anyway, I don't see a problem
 with things as they are.
Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
 Finding a way for the average user to do safe concurrent programming is an
 entirely different issue in my opinion, and has only really been "solved," in
 my opinion, in the functional programming realm.  And that's by eliminating
 data sharing--the bane of imperative languages everywhere.
D will eliminate implicit data sharing. To share data, you'll have to mark it as shared, and with the marking will come extra help in fences and synchronization. I've looked at the two classic multithreaded problems - double checked locking, and sequential consistency between threads. This model prevents both of them from happening.
So "shared" will tell the compiler to automatically fence, etc? Will any actual enforcement be done? And if so, will this be at compile time, run time, or both?
 I disagree.  D is a systems language first and foremost.  Much of the
 rest can be done in library code.  That isn't to say that I wouldn't
 like improved multiprogramming support in the language for the things
 that are awkward to do in library code (a thread-local storage class,
 for example), but trying to prevent the user from shooting himself in
 the foot is unnecessary.
 Particularly if doing so incurs a runtime
 cost that is not avoidable.
It is avoidable if you're willing to insert a cast. Putting in the cast says "I know how to handle the wild west, let me do it." The cast has zero runtime cost.
I think that cast is already used far too much as a standard programming mechanism in D 2.0. And I'll admit that I don't entirely understand why you don't like const_cast but assertUnique or whatever does exactly that behind the scenes. Should we consider cast to be an evil red flag-throwing feature or not?
 There was some talk in the C++0x memory model discussion that Intel
 was actually planning on providing equivalent or stronger guarantees
 for future processors rather than weaker ones.  I'll admit to having
 been very surprised at the time, but apparently they feel that they
 can do so and still provide the performance people expect.  I guess
 the resounding failure of the Itanic forced them to rethink what was
 required for a successful new processor design.  If I remember
 correctly, it was Paul McKenney that brought this up if you feel like
 searching the archives.
Intel may be reacting to the disastrous problems conventional languages have with this. If it is solved (and I think we have a credible solution), Intel may change their direction.
That's certainly possible. But I do think it would require the solution to be pervasive rather than just in D if Intel were to pay attention. That said, I'd most prefer release consistency for a hardware memory model (somewhat like the Itanium) combined with hardware transactional memory. I'm actually a bit disappointed that the Itanium wasn't successful. The basic design was solid. Sean
Jul 31 2008
next sibling parent superdan <super dan.org> writes:
Sean Kelly Wrote:

 That's certainly possible.  But I do think it would require the solution to
 be pervasive rather than just in D if Intel were to pay attention.  That
 said, I'd most prefer release consistency for a hardware memory model
 (somewhat like the Itanium) combined with hardware transactional
 memory.  I'm actually a bit disappointed that the Itanium wasn't
 successful.  The basic design was solid.
haven't read bartosz' stuff yet, so no comment on that. but with all due respect. about itanium's design. what a piece of rotten shit that is. they use predicated execution like it's jesus on tv. of course that didn't catch up. itanium was a stillborn from day 1.
Jul 31 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
From talking to people who do large scale multithreaded Java programs, it is not fine. The problem is that there is no way to look at a non-trivial piece of code that you didn't write, and determine if it has dependencies on sequential consistency or not. I'm not arguing that a thread expert cannot make a thread correct program in Java and C++. They can. The problem is the inability to verify such correctness, no help is available from the language, and the dearth of such experts.
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
 Will any actual
 enforcement be done?  And if so, will this be at compile time, run time, or
 both?
Compile time - it's part of the static type checking system.
 It is avoidable if you're willing to insert a cast. Putting in the cast
 says "I know how to handle the wild west, let me do it." The cast has
 zero runtime cost.
I think that cast is already used far too much as a standard programming mechanism in D 2.0. And I'll admit that I don't entirely understand why you don't like const_cast but assertUnique or whatever does exactly that behind the scenes. Should we consider cast to be an evil red flag-throwing feature or not?
Cast is the red flag raising feature. The thing about it is that when you review code, the cast is where you look for bugs. With Java and C++, you have *no clue* where to look for bugs. It reduces the problem domain from the entire program to a (hopefully) manageable small subset.
Jul 31 2008
next sibling parent reply superdan <super dan.org> writes:
Walter Bright Wrote:

 Sean Kelly wrote:
 Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
From talking to people who do large scale multithreaded Java programs, it is not fine. The problem is that there is no way to look at a non-trivial piece of code that you didn't write, and determine if it has dependencies on sequential consistency or not. I'm not arguing that a thread expert cannot make a thread correct program in Java and C++. They can. The problem is the inability to verify such correctness, no help is available from the language, and the dearth of such experts.
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
Jul 31 2008
next sibling parent reply superdan <super dan.org> writes:
Walter Bright Wrote:

 superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
i grok that. my problem is that your shared doesn't help me with writing good code in that case. ++x is just wrong for shared x. i'd rather have it disabled or somethin'.
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 i grok that. my problem is that your shared doesn't help me with
 writing good code in that case. ++x is just wrong for shared x. i'd
 rather have it disabled or somethin'.
Actually, the current plan is that ++ would be disabled for shared lvalues. Reads and writes to them would be done through intrinsic functions, which would make clear the order in which reads and writes are done. Sure, it won't be pretty, but there won't be any ambiguity of the order in which things happen.
Aug 01 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 superdan wrote:
 i grok that. my problem is that your shared doesn't help me with
 writing good code in that case. ++x is just wrong for shared x. i'd
 rather have it disabled or somethin'.
Actually, the current plan is that ++ would be disabled for shared lvalues. Reads and writes to them would be done through intrinsic functions, which would make clear the order in which reads and writes are done. Sure, it won't be pretty, but there won't be any ambiguity of the order in which things happen.
A totally worthwhile tradeoff IMO. The alternative would be to have ++ call INC if supported or a CAS loop if not, and that's a hidden cost that may surprise users. It could always be enabled later if needed anyway. Oh, and darn you for getting me moderately enthusiastic for D 2.0 :-) Sean
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Sure, it won't be pretty, but there won't be any ambiguity of the order
 in which things happen.
A totally worthwhile tradeoff IMO. The alternative would be to have ++ call INC if supported or a CAS loop if not, and that's a hidden cost that may surprise users. It could always be enabled later if needed anyway.
I'm surprised, we expected much more flak about that <g>. The idea is to screw everything down tight like this, see how it goes, and then experience will tell us where we need to loosen things up.
 Oh, and darn you for getting me moderately enthusiastic for
 D 2.0 :-)
I for one am very enthusiastic about the new threading model. The real validation would be when other languages start copying it!
Aug 01 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe. Sean
Aug 01 2008
next sibling parent reply superdan <super dan.org> writes:
Sean Kelly Wrote:

 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe. Sean
i don't think so. reading must be still fenced if at least one thread writes to it. walt is correct.
Aug 01 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from superdan (super dan.org)'s article
 Sean Kelly Wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
i don't think so. reading must be still fenced if at least one thread writes to
it. walt is correct. Yeah, but the "i++" is safe, which is all I was implying. Technically the read doesn't even need to be fenced so long as the reader doesn't care if they then operate on a stale value, but it's rare for that to be the case. However, I think I do use this approach in core.Thread in Tango for a flag somewhere. Kinda risky, but I don't want to pay for the ~70 cycles a lock would require and I really don't care if the value is a bit stale. But in these instances, I think it's totally okay to require the user to take extra steps to indicate that this is his intention. core.Atomic, for example, has msync.raw to indicate that no synchronization should occur, but a bidirectional fence is the default if no sync flag is passed. Sean
Aug 01 2008
parent reply superdan <super dan.org> writes:
Sean Kelly Wrote:

 == Quote from superdan (super dan.org)'s article
 Sean Kelly Wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 superdan wrote:
 Walter Bright Wrote:
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
yech. so i write this: ++a; ++b; ++c; and very different code comes down the pike depending on a or b or c being shared. not easy to clarify the code is correct. this ain't cool.
If conventional code were generated for i++, and i was accessed from multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
i don't think so. reading must be still fenced if at least one thread writes to
it. walt is correct. Yeah, but the "i++" is safe, which is all I was implying. Technically the read doesn't even need to be fenced so long as the reader doesn't care if they then operate on a stale value, but it's rare for that to be the case. However, I think I do use this approach in core.Thread in Tango for a flag somewhere. Kinda risky, but I don't want to pay for the ~70 cycles a lock would require and I really don't care if the value is a bit stale. But in these instances, I think it's totally okay to require the user to take extra steps to indicate that this is his intention. core.Atomic, for example, has msync.raw to indicate that no synchronization should occur, but a bidirectional fence is the default if no sync flag is passed.
makes sense. but i guess we agree that that is the rare case in which you're ok with a race. the usual case is you don't want a race. so i think it's fair that the rare case requires a cast. walt seems to have gotten the default right as far as i can tell.
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 makes sense. but i guess we agree that that is the rare case in which
 you're ok with a race. the usual case is you don't want a race. so i
 think it's fair that the rare case requires a cast. walt seems to
 have gotten the default right as far as i can tell.
It's not just me. There are several people who've been hammering away at how this needs to work, including Andrei, Bartosz, David Held, Brad Roberts, and Eric Niebler.
Aug 01 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 If conventional code were generated for i++, and i was accessed from
 multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
If you've got only one thread, why is it shared ? If it is shared, there's the possibility of multiple threads, and so the code is wrong wrong wrong.
Aug 01 2008
next sibling parent reply superdan <super dan.org> writes:
Walter Bright Wrote:

 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 If conventional code were generated for i++, and i was accessed from
 multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
If you've got only one thread, why is it shared ? If it is shared, there's the possibility of multiple threads, and so the code is wrong wrong wrong.
i think he means a different case. you have many threads alright. but only one is incrementin'. others are just readin'.
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 Walter Bright Wrote:
 
 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s
 article
 If conventional code were generated for i++, and i was accessed
 from multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
If you've got only one thread, why is it shared ? If it is shared, there's the possibility of multiple threads, and so the code is wrong wrong wrong.
i think he means a different case. you have many threads alright. but only one is incrementin'. others are just readin'.
If Sean means that the code is synchronized so only one thread has access, he is correct. In the proposed threading model, within a synchronized function, the shared object data can be accessed without fences and the ++ will work. Essentially, within a synchronized function, the 'this' object becomes tail-shared. I know, AAAIIIEEEEE!
Aug 01 2008
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 If conventional code were generated for i++, and i was accessed from
 multiple threads, the code is *broken*.
Not necessarily. If i is a 32-bit number and only one thread is doing the writing then the code could be perfectly safe.
If you've got only one thread, why is it shared ? If it is shared, there's the possibility of multiple threads, and so the code is wrong wrong wrong.
Only one writer, multiple readers. But this is assuming the INC is issued to the CPU rather than the compiler deciding to just hold onto the value in a register or something. ie. I think "shared" implies more than fences, yes? It's also an indication to the compiler than certain optimizations may not be performed, roughly similar to 'volatile' in D 1.0. Sean
Aug 01 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
From talking to people who do large scale multithreaded Java programs, it is not fine. The problem is that there is no way to look at a non-trivial piece of code that you didn't write, and determine if it has dependencies on sequential consistency or not. I'm not arguing that a thread expert cannot make a thread correct program in Java and C++. They can. The problem is the inability to verify such correctness, no help is available from the language, and the dearth of such experts.
That's the problem with providing such fundamental support for lock-free programming: people will try it, and they'll invariably get it wrong. This is actually the reason why I like the minimalist approach of D 1.0 with 'volatile'. Support for lock-free is sufficiently subtle that it's unlikely to be used outside of library code.
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
 Will any actual
 enforcement be done?  And if so, will this be at compile time, run time, or
 both?
Compile time - it's part of the static type checking system.
I've got to admit that I actually like this idea. It's a breaking change that will trigger run-time failures in code when the feature is deployed, but in the kind of multithreaded apps I write I'd be labeling perhaps two variable declarations in the entire app. Would it be possible to do something like this and have the compiler realize it's safe: class SharedObj { void go() {} } shared Mutex m; shared SharedObj o; static this() { m = new Mutex; o = new SharedObj; } void someFunc() { synchronized( m ) { o.go(); } }
 It is avoidable if you're willing to insert a cast. Putting in the cast
 says "I know how to handle the wild west, let me do it." The cast has
 zero runtime cost.
I think that cast is already used far too much as a standard programming mechanism in D 2.0. And I'll admit that I don't entirely understand why you don't like const_cast but assertUnique or whatever does exactly that behind the scenes. Should we consider cast to be an evil red flag-throwing feature or not?
Cast is the red flag raising feature. The thing about it is that when you review code, the cast is where you look for bugs. With Java and C++, you have *no clue* where to look for bugs. It reduces the problem domain from the entire program to a (hopefully) manageable small subset.
Java and C++ have cast too, though. Unfortunately, it's not easy to grep for 'cast' in Java because of the syntax, but I use the C++ style casts religiously there and I like that they "jump out" at me when reading the code. From a quick scan of an old project of mine, outside systems code where casting is often necessary as a matter of course, the precious few casts in the app are mostly for warning-free comparisons of signed and unsigned integers in situations I know the values will be in bounds. Which reminds me... weren't we going to get tighter conversion rules for concrete types? I'd love to have the D compiler yell at me for these things like my C++ compiler does. Back on track... I suppose I'm just worried that my apps will end up with casts all over the place simply to allow me to operate normally, thus diluting the usefulness of this red flag. But that's idle speculation so perhaps my concern is unfounded.
Jul 31 2008
next sibling parent reply superdan <super dan.org> writes:
Sean Kelly Wrote:

 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
From talking to people who do large scale multithreaded Java programs, it is not fine. The problem is that there is no way to look at a non-trivial piece of code that you didn't write, and determine if it has dependencies on sequential consistency or not. I'm not arguing that a thread expert cannot make a thread correct program in Java and C++. They can. The problem is the inability to verify such correctness, no help is available from the language, and the dearth of such experts.
That's the problem with providing such fundamental support for lock-free programming: people will try it, and they'll invariably get it wrong. This is actually the reason why I like the minimalist approach of D 1.0 with 'volatile'. Support for lock-free is sufficiently subtle that it's unlikely to be used outside of library code.
fraid you might have a slightly specialized definition of what lock-free code is. i think you say that cas-based shit is lock free. but here, this is lock free: data = 5.4; dataThere = true; people use lock-free *everywhere*. just they don't call it that way. they just synchronize through atomic assignments. i'm not sure at this point how d's shared will improve the above. if i understand that shit correctly you define data and dataThere as shared. then you know assignments occur in the proper sequence (because of the inserted fences and shit). if they weren't shared they could be assigned in the wrong order but nobody could tell. it's like the shit in the forest that don't stink because nobody's smellin'. and if they weren't shared they wouldn't be shareable to start with. so the whole shit works. is that true walt?
 So "shared" will tell the compiler to automatically fence, etc?
Yes.
 Will any actual
 enforcement be done?  And if so, will this be at compile time, run time, or
 both?
Compile time - it's part of the static type checking system.
I've got to admit that I actually like this idea. It's a breaking change that will trigger run-time failures in code when the feature is deployed, but in the kind of multithreaded apps I write I'd be labeling perhaps two variable declarations in the entire app.
yeh same here. good mt apps share little and with care.
  Would it be possible to do
 something like this and have the compiler realize it's safe:
 
     class SharedObj
     {
         void go() {}
     }
 
     shared Mutex m;
     shared SharedObj o;
 
     static this()
     {
         m = new Mutex;
         o = new SharedObj;
     }
 
     void someFunc()
     {
         synchronized( m )
         {
             o.go();
         }
     }
 
 It is avoidable if you're willing to insert a cast. Putting in the cast
 says "I know how to handle the wild west, let me do it." The cast has
 zero runtime cost.
I think that cast is already used far too much as a standard programming mechanism in D 2.0. And I'll admit that I don't entirely understand why you don't like const_cast but assertUnique or whatever does exactly that behind the scenes. Should we consider cast to be an evil red flag-throwing feature or not?
Cast is the red flag raising feature. The thing about it is that when you review code, the cast is where you look for bugs. With Java and C++, you have *no clue* where to look for bugs. It reduces the problem domain from the entire program to a (hopefully) manageable small subset.
Java and C++ have cast too, though. Unfortunately, it's not easy to grep for 'cast' in Java because of the syntax, but I use the C++ style casts religiously there and I like that they "jump out" at me when reading the code. From a quick scan of an old project of mine, outside systems code where casting is often necessary as a matter of course, the precious few casts in the app are mostly for warning-free comparisons of signed and unsigned integers in situations I know the values will be in bounds. Which reminds me... weren't we going to get tighter conversion rules for concrete types? I'd love to have the D compiler yell at me for these things like my C++ compiler does.
fuck yeah walt. put me down for that one too.
Jul 31 2008
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 fraid you might have a slightly specialized definition of what
 lock-free code is. i think you say that cas-based shit is lock free.
 but here, this is lock free:
 
 data = 5.4; dataThere = true;
 
 people use lock-free *everywhere*. just they don't call it that way.
 they just synchronize through atomic assignments.
 
 i'm not sure at this point how d's shared will improve the above. if
 i understand that shit correctly you define data and dataThere as
 shared. then you know assignments occur in the proper sequence
 (because of the inserted fences and shit). if they weren't shared
 they could be assigned in the wrong order but nobody could tell. it's
 like the shit in the forest that don't stink because nobody's
 smellin'. and if they weren't shared they wouldn't be shareable to
 start with. so the whole shit works. is that true walt?
Yes.
Aug 01 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from superdan (super dan.org)'s article
 Sean Kelly Wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
From talking to people who do large scale multithreaded Java programs, it is not fine. The problem is that there is no way to look at a non-trivial piece of code that you didn't write, and determine if it has dependencies on sequential consistency or not. I'm not arguing that a thread expert cannot make a thread correct program in Java and C++. They can. The problem is the inability to verify such correctness, no help is available from the language, and the dearth of such experts.
That's the problem with providing such fundamental support for lock-free programming: people will try it, and they'll invariably get it wrong. This is actually the reason why I like the minimalist approach of D 1.0 with 'volatile'. Support for lock-free is sufficiently subtle that it's unlikely to be used outside of library code.
fraid you might have a slightly specialized definition of what lock-free code
is. i think you say that cas-based shit is lock free. but here, this is lock free:
 data = 5.4;
 dataThere = true;
 people use lock-free *everywhere*. just they don't call it that way. they just
synchronize through atomic assignments. Yeah that's true. What drives me crazy about this is that there's no way to tell from inspection whether the programmer knew what they were doing. You end up having to check all the uses of 'data' to find out. I guess this is Walter's point about static checking. If 'data' were shared then I could trust that it would "just work." In Tango, you'd do: atomicStore( data, 5.4 ); And that would label the assignment as "safe" to a reader, but other uses of 'data' could still be broken.
 i'm not sure at this point how d's shared will improve the above. if i
understand that shit correctly you define data and dataThere as shared. then you know assignments occur in the proper sequence (because of the inserted fences and shit). if they weren't shared they could be assigned in the wrong order but nobody could tell. it's like the shit in the forest that don't stink because nobody's smellin'. and if they weren't shared they wouldn't be shareable to start with. so the whole shit works. is that true walt? This sounds right. My only concern for the injected fences is that it won't always result in optimal code for what the user is doing. But it will be safe, which I guess is pretty important (by "optimal" I mean that you don't always need fences for an operation depending on the hardware and on whether you care about code movement across the operation). Sean
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 This sounds right.  My only concern for the injected fences is that it won't
always
 result in optimal code for what the user is doing.  But it will be safe, which
I
 guess is pretty important (by "optimal" I mean that you don't always need
fences
 for an operation depending on the hardware and on whether you care about code
 movement across the operation).
You're right, it won't always be optimal. The idea is to get it right and then just optimize the bottlenecks.
Aug 02 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Would it be possible to do
 something like this and have the compiler realize it's safe:
 
     class SharedObj
     {
         void go() {}
     }
 
     shared Mutex m;
     shared SharedObj o;
 
     static this()
     {
         m = new Mutex;
         o = new SharedObj;
     }
 
     void someFunc()
     {
         synchronized( m )
         {
             o.go();
         }
     }
I don't know, but I doubt it.
 Cast is the red flag raising feature. The thing about it is that when
 you review code, the cast is where you look for bugs. With Java and C++,
 you have *no clue* where to look for bugs. It reduces the problem domain
 from the entire program to a (hopefully) manageable small subset.
Java and C++ have cast too, though.
But that is useless for multithreading, because Java and C++ types have no notion of sharing.
 Which
 reminds me... weren't we going to get tighter conversion rules for concrete
 types?  I'd love to have the D compiler yell at me for these things like my
 C++ compiler does.
All in goood time, my pretty <rubs hands>
 Back on track... I suppose I'm just worried that my apps will end up with
 casts all over the place simply to allow me to operate normally, thus
 diluting the usefulness of this red flag.  But that's idle speculation
 so perhaps my concern is unfounded.
I don't know how it will work out yet in practice, either. But I suspect if casts wind up all over the place, that may be a sign that there are too many connection points between the shared and unshared worlds, and perhaps a code refactoring is in order.
Jul 31 2008
prev sibling parent reply superdan <super dan.org> writes:
Sean Kelly Wrote:

 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 In my opinion, the easiest way to describe the hardware side of things is
 simply to say that the CPU does the exact same thing as the optimizer in
 the compiler, only it does this dynamically as the code is executing.  The
 rest just involves ideas for how to constrain CPU and compiler optimizations
 so the app behaves as expected when concurrency is involved.  In your defense,
 "volatile" is a perfectly suitable minimum for D, so you did get the gist of
 the issue, even at the outset.  The catch is that, while "volatile" controls
 the compiler, you still need to control the CPU, so inline ASM is required
 as well.  Fortunately, D has that :-)  So please give yourself a bit more
 credit here.  D1 works perfectly well for concurrent programming.  It just
 support this is a sufficiently non-obvious way that only people who
 understand the issues involved are likely to realize it.  But as most of
 this stuff should really be in a library anyway, I don't see a problem
 with things as they are.
Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
i'm afraid c++ and c++0x and java are "actually fine" to write multiprocessing code if the coder is fucking superman on steroids after an overdose of ritalin. as far as threads are concerned these are as good as brainfuck to code in. you also say d1 is perfectly fine to do multiprocessing in. i think that's at best naive. sorry sean.
Jul 31 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from superdan (super dan.org)'s article
 Sean Kelly Wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 In my opinion, the easiest way to describe the hardware side of things is
 simply to say that the CPU does the exact same thing as the optimizer in
 the compiler, only it does this dynamically as the code is executing.  The
 rest just involves ideas for how to constrain CPU and compiler optimizations
 so the app behaves as expected when concurrency is involved.  In your defense,
 "volatile" is a perfectly suitable minimum for D, so you did get the gist of
 the issue, even at the outset.  The catch is that, while "volatile" controls
 the compiler, you still need to control the CPU, so inline ASM is required
 as well.  Fortunately, D has that :-)  So please give yourself a bit more
 credit here.  D1 works perfectly well for concurrent programming.  It just
 support this is a sufficiently non-obvious way that only people who
 understand the issues involved are likely to realize it.  But as most of
 this stuff should really be in a library anyway, I don't see a problem
 with things as they are.
Java has synchronization and volatile, and it isn't good enough.
But volatile in Java is completely different. And Java doesn't support inline ASM. That said, Java post JSR-133 (ie. Java today) is actually fine. The C++ 0x people simply didn't copy Java because the Java memory model is too strict to appease the performance-crazed folks in the group :-)
i'm afraid c++ and c++0x and java are "actually fine" to write multiprocessing
code if the coder is fucking superman on steroids after an overdose of ritalin. as far as threads are concerned these are as good as brainfuck to code in. you also say d1 is perfectly fine to do multiprocessing in. i think that's at best naive. sorry sean. No problem. Just because I think they're all functional doesn't mean I think they make for easily verifiable or safe code. I'd agree with you that most actual multithreaded code in these languages is garbage. Though most plain old code I've seen is garbage anyway, so I guess it's no surprise that the actually difficult stuff would follow suit. As far as verifiability is concerned though, CSP and the other process algebras are darn nice. Sean
Jul 31 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 i'm afraid c++ and c++0x and java are "actually fine" to write
 multiprocessing code if the coder is fucking superman on steroids
 after an overdose of ritalin.
There's also the issue of the person who thinks they know how to write multithreaded code, but don't. Want an example? Just look at some of my older code. This code may "work" well enough that the problems don't appear until years later. Then what? I remember the reaction to Herb Sutter showing some of the things that can go wrong to multithreaded programmers - it was holy ****, I had no idea! Having no compiler help with this is like turning off static type checking. Sure, if you're a good programmer, you don't need static type checking! I believe there is a growing need to be able to statically *prove* things about a program. If that can be done, you don't have to rely on experts being always right. Java, for example, can prove your program is memory safe. Certain classes of bugs cannot happen with Java programs. The more classes of bugs that can be defined out of existence, the easier it will be to verify correctness regardless of the expertise of the programmer.
Jul 31 2008
parent reply JAnderson <ask me.com> writes:
Walter Bright wrote:
 Having no compiler help with this is like turning off static type 
 checking. Sure, if you're a good programmer, you don't need static type 
 checking!
 
Lets all just program in Python or one of those other untypesafe languages :) -Joel
Jul 31 2008
parent superdan <super dan.org> writes:
JAnderson Wrote:

 Walter Bright wrote:
 Having no compiler help with this is like turning off static type 
 checking. Sure, if you're a good programmer, you don't need static type 
 checking!
 
Lets all just program in Python or one of those other untypesafe languages :)
python is typesafe. just not statically.
Jul 31 2008
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 Java has synchronization and volatile, and it isn't good enough.
Java is some years old, while Scala is a new language that runs on the JavaVM that is slowly growing in its usage. In Scala people often use Actor-based concurrency (and someone is starting to use Actors in Java too). Scala contains some 'modern' things, that D may take a look at, instead of using just C/C++/C++0x/Java/Python as reference. Bye, bearophile
Jul 31 2008
prev sibling next sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 30 de julio a las 23:22 me escribiste:
 Steven Schveighoffer wrote:
"Walter Bright" wrote
http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data.
Nearly all global data is assumed to be and treated as if it were unshared. So making unshared the default is the right solution. And frankly, if you're using a lot of global variables, you might want to reevaluate what you're doing. Lots of global variables is the 80's style of programming :-)
Tell that to singleton-monkeys =P -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- ¿Qué será lo que hace que una brújula siempre marque el norte? - Ser aguja, nada más, y cumplir su misión. -- Ricardo Vaporeso
Jul 31 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Leandro Lucarella wrote:
 Tell that to singleton-monkeys =P
Yeah, and singletons suffer from the double-checked locking bug! Bartosz even found one of those in my code, and I should know better!
Jul 31 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data.
Nearly all global data is assumed to be and treated as if it were unshared. So making unshared the default is the right solution. And frankly, if you're using a lot of global variables, you might want to reevaluate what you're doing. Lots of global variables is the 80's style of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
 I would hazard to guess that adopting this would cause a larger rift than 
 const.
Perhaps. But the alternative is the current wild west approach to multithreaded programming. With the proliferation of multicore computers, the era where this is acceptable is coming to an end.
Yeah, because all us cowboys don't like your kind. Maybe we need to get us a rope and have a lynchin. Seriously, how can you say that the current threadding tools are 'uncontrolled' (i.e. wild west)? I spend lots of time thinking about multithreadded issues, and make sure my software works properly. I think the level of quality for threadding issues depends on the coder, not the tools. In the case of shared/unshared, it's not going to change anything, except now I have to declare things I didn't have to declare before. I.e. having shared/unshared is going to be just as wild as before. I may be wrong, and this shared/unshared thing will be really great for people. But I think it needs a lot of work before it's helpful. In its current incarnation, I'll call it the 'shared wild west' approach :P
 Second, the fact that you can't implicitly cast shared to unshared and 
 vice versa.  It's going to make communication between both 'worlds' very 
 error prone, as you will be required to cast for any call from one to the 
 other.
I think the reverse is true. Moving data between those worlds is dangerous and needs to be carefully vetted, so requiring an explicit cast will reduce the chance of this happening unintentionally.
Except now instead of the compiler helping you, you have pushed aside that help and said 'I know what I'm doing'. Oops, back to the wild west :)
 People will do this just to get their code to work, without thinking 
 about the consequences.
True, but having it happen implicitly is even worse, because there's no indication that it is happening.
dmd mycode.d Error: when calling foo(shared int *), cannot pass int * edit mycode.d, cast to shared int * OK, now it works :) Probably without any problems, because the compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread! But the result is, we're back to the same model as before. And now I have to cast everything. Annoying.
 Even those that do think about the consequences, can't have the compiler 
 statically check the cast in either direction, so once you cast, you lose 
 all the benefit.
But still, you're far better off than the current wild west approach where everything is implicitly shared with no protection whatsoever. The popular double checked locking bug will be impossible to code in D without stuffing in explicit casts. The casts will be a red flag that the programmer is making a mistake.
Please let me decide whether I'm far better off. I don't need protection from stuff that doesn't matter. I will still have to lock shared data, and still have to cast to get things to work, so I'm not better off. You can't tell me otherwise, because all this stuff is a figment of your imagination. You have no proof. Until you can show me that I'm better off with an actual example, then I believe we both are equally right :) -Steve
Jul 31 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were 
 unshared. So making unshared the default is the right solution. And 
 frankly, if you're using a lot of global variables, you might want to 
 reevaluate what you're doing. Lots of global variables is the 80's style 
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more. (Programming languages started out with everything being global data, and has moved away from that ever since.)
 Yeah, because all us cowboys don't like your kind.  Maybe we need to get us 
 a rope and have a lynchin.  Seriously, how can you say that the current 
 threadding tools are 'uncontrolled' (i.e. wild west)?
Because of the common multithreaded bug http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html for one example. There is no threading tool I'm aware of that can prevent or detect such bugs.
 I spend lots of time 
 thinking about multithreadded issues, and make sure my software works 
 properly.  I think the level of quality for threadding issues depends on the 
 coder, not the tools.
I believe the tools can make it easier.
 In the case of shared/unshared, it's not going to 
 change anything, except now I have to declare things I didn't have to 
 declare before.  I.e. having shared/unshared is going to be just as wild as 
 before.
Why? First of all, unshared data isn't going to have sequential or sync issues, by definition. Already, you've cut the problem domain down by a huge chunk. Next, shared data access will come with fences or sync. That isn't going to guarantee no deadlocks, but it will guarantee sequential consistency, and at the very least will dramatically cut the problem domain down.
 Except now instead of the compiler helping you, you have pushed aside that 
 help and said 'I know what I'm doing'.  Oops, back to the wild west :)
If you want the wild west, you have it, if you want compiler help instead, you got it. How is that worse than C++ or Java, where you always have the wild west and no help at all?
 True, but having it happen implicitly is even worse, because there's no 
 indication that it is happening.
dmd mycode.d Error: when calling foo(shared int *), cannot pass int * edit mycode.d, cast to shared int * OK, now it works :) Probably without any problems, because the compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread! But the result is, we're back to the same model as before. And now I have to cast everything. Annoying.
Non-shared can be implicitly cast to shared, as that is always safe. Just not the other way.
 Please let me decide whether I'm far better off.
Ok. D offers both - and for the guy maintaining your code, there'll at least be clear indications of where to look for the source of elusive threading bugs. Optlink currently has a threading bug in it. I have no idea where to look for it in the source code.
 I don't need protection 
 from stuff that doesn't matter.  I will still have to lock shared data, and 
 still have to cast to get things to work, so I'm not better off.  You can't 
 tell me otherwise, because all this stuff is a figment of your imagination. 
 You have no proof.  Until you can show me that I'm better off with an actual 
 example, then I believe we both are equally right :)
I didn't think I'd convince anyone the first time around. But I'm patient <g>.
Jul 31 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were 
 unshared. So making unshared the default is the right solution. And 
 frankly, if you're using a lot of global variables, you might want to 
 reevaluate what you're doing. Lots of global variables is the 80's style 
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
 (Programming languages started out with everything being global data, and 
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
 Yeah, because all us cowboys don't like your kind.  Maybe we need to get 
 us a rope and have a lynchin.  Seriously, how can you say that the 
 current threadding tools are 'uncontrolled' (i.e. wild west)?
Because of the common multithreaded bug http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html for one example. There is no threading tool I'm aware of that can prevent or detect such bugs.
As described on that page, the problem was fixed with JDK 5, and can be solved using the volatile modifier.
 I spend lots of time thinking about multithreadded issues, and make sure 
 my software works properly.  I think the level of quality for threadding 
 issues depends on the coder, not the tools.
I believe the tools can make it easier.
I do too. But I don't see this one being that tool.
 In the case of shared/unshared, it's not going to change anything, except 
 now I have to declare things I didn't have to declare before.  I.e. 
 having shared/unshared is going to be just as wild as before.
Why? First of all, unshared data isn't going to have sequential or sync issues, by definition. Already, you've cut the problem domain down by a huge chunk. Next, shared data access will come with fences or sync. That isn't going to guarantee no deadlocks, but it will guarantee sequential consistency, and at the very least will dramatically cut the problem domain down.
Are you saying that there will be an automatic notion by the compiler that implements the fences, or that I have to add them on top? If the former, then I don't remember reading that in the article, and that does sound promising.
 Except now instead of the compiler helping you, you have pushed aside 
 that help and said 'I know what I'm doing'.  Oops, back to the wild west 
 :)
If you want the wild west, you have it, if you want compiler help instead, you got it. How is that worse than C++ or Java, where you always have the wild west and no help at all?
What I'm saying is that if you have to cast just to get something working, you have defeated the system. I'm not saying that you are back to the wild west *by choice*, I'm saying you will most likely end up having to do that just to get it to work. I'm thinking of many cases where you have to use old code, or old libraries that don't have this feature, or code written by someone unaware of the details.
 True, but having it happen implicitly is even worse, because there's no 
 indication that it is happening.
dmd mycode.d Error: when calling foo(shared int *), cannot pass int * edit mycode.d, cast to shared int * OK, now it works :) Probably without any problems, because the compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread! But the result is, we're back to the same model as before. And now I have to cast everything. Annoying.
Non-shared can be implicitly cast to shared, as that is always safe. Just not the other way.
How is that possible? shared int *x; void foo(shared int *y) { x = y; } int *x2; void bar() { foo(x2); } After calling bar, isn't x2 now both shared (as x) and unshared at the same time? I think you need casts for both ways. I think shared/unshared is analogous to mutable/invariant. There is no implicit cast.
 Please let me decide whether I'm far better off.
Ok. D offers both - and for the guy maintaining your code, there'll at least be clear indications of where to look for the source of elusive threading bugs.
All I was saying with that comment is the notion that 'Walter knows best' is not a convincing argument.
 Optlink currently has a threading bug in it. I have no idea where to look 
 for it in the source code.
Threading problems are very difficult to find. I don't think the shared/unshared model will help with that, especially since most likely you will have to break it to get things working. I generally can only find multithreading issues with lots of logging, and running through potentially offending code in my head. I think that this idea has potential, and could possibly lead to something that is helpful. The thinking is in the right direction. But I'm not convinced that this incarnation will be helpful. I'd have to see examples of how this would be useful to understand it better. And please PLEASE make it backwards compatible. I don't see any reason why it must be shared that is the tagged value. -Steve
Aug 01 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were
 unshared. So making unshared the default is the right solution. And
 frankly, if you're using a lot of global variables, you might want to
 reevaluate what you're doing. Lots of global variables is the 80's style
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
 (Programming languages started out with everything being global data, and
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
I'm hoping that 'shared' will force programmers to think about what they're doing a bit more. A typical multithreaded app should have extremely little shared data. One thing I'm not sure of, though, is if I write a single- threaded app, will I need to label anything shared? Functionally I don't, since having everything thread-local is exactly what I need, but I'm not sure if the compiler will yell at me anyway. I'm guessing it will, which would be a bit annoying, but it would "future proof" the app for adding multithreading later, so perhaps it's okay. Sean
Aug 01 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Sean Kelly" wrote
 == Quote from Steven Schveighoffer article
 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were
 unshared. So making unshared the default is the right solution. And
 frankly, if you're using a lot of global variables, you might want to
 reevaluate what you're doing. Lots of global variables is the 80's 
 style
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
 (Programming languages started out with everything being global data, 
 and
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
I'm hoping that 'shared' will force programmers to think about what they're doing a bit more. A typical multithreaded app should have extremely little shared data. One thing I'm not sure of, though, is if I write a single- threaded app, will I need to label anything shared? Functionally I don't, since having everything thread-local is exactly what I need, but I'm not sure if the compiler will yell at me anyway. I'm guessing it will, which would be a bit annoying, but it would "future proof" the app for adding multithreading later, so perhaps it's okay.
I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write. I think at the very least, for this to be palatable, there needs to be another modifier that unifies shared and unshared. Similar to how const unifies mutable and invariant. -Steve
Aug 01 2008
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 "Sean Kelly" wrote
 == Quote from Steven Schveighoffer article
 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were
 unshared. So making unshared the default is the right solution. And
 frankly, if you're using a lot of global variables, you might want to
 reevaluate what you're doing. Lots of global variables is the 80's
 style
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
 (Programming languages started out with everything being global data,
 and
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
I'm hoping that 'shared' will force programmers to think about what they're doing a bit more. A typical multithreaded app should have extremely little shared data. One thing I'm not sure of, though, is if I write a single- threaded app, will I need to label anything shared? Functionally I don't, since having everything thread-local is exactly what I need, but I'm not sure if the compiler will yell at me anyway. I'm guessing it will, which would be a bit annoying, but it would "future proof" the app for adding multithreading later, so perhaps it's okay.
I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write.
Darnit, you're right. That's just like 'volatile' in C++. In fact, it's the primary reason why I dislike the const system in D 2.0.
 I think at the very least, for this to be palatable, there needs to be
 another modifier that unifies shared and unshared.  Similar to how const
 unifies mutable and invariant.
You could be right. Though that means yet another label and all the baggage that goes with it. Sean
Aug 01 2008
prev sibling parent reply superdan <super dan.org> writes:
Steven Schveighoffer Wrote:

 "Sean Kelly" wrote
 == Quote from Steven Schveighoffer article
 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were
 unshared. So making unshared the default is the right solution. And
 frankly, if you're using a lot of global variables, you might want to
 reevaluate what you're doing. Lots of global variables is the 80's 
 style
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
 (Programming languages started out with everything being global data, 
 and
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
I'm hoping that 'shared' will force programmers to think about what they're doing a bit more. A typical multithreaded app should have extremely little shared data. One thing I'm not sure of, though, is if I write a single- threaded app, will I need to label anything shared? Functionally I don't, since having everything thread-local is exactly what I need, but I'm not sure if the compiler will yell at me anyway. I'm guessing it will, which would be a bit annoying, but it would "future proof" the app for adding multithreading later, so perhaps it's okay.
I'm thinking more in the case of functions. If I have a function foo, and I want to pass my shared data version to it, I need to re-implement foo with the parameters as being shared. Imagine a function with several parameters, in which you want to pass a combination of shared/unshared. That's 2^n variations you have to write.
but the code there *is* different. there are fence combinations & shit. i guess in such cases you'd need a template.
 I think at the very least, for this to be palatable, there needs to be 
 another modifier that unifies shared and unshared.  Similar to how const 
 unifies mutable and invariant.
sounds interesting but i don't get it. we have: invariant == never changes const == i won't change it mutable == fuck you, i'm changing in the shared cases we have: unshared == never seen by 2 threads ? == ? shared == fuck you, i'm shared so how would that go. i won't share it? i won't write to it? (that's useless bc of read fences.) anyway this is intriguing shit. unification is power.
Aug 01 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from superdan (super dan.org)'s article
 in the shared cases we have:
 unshared == never seen by 2 threads
 ? == ?
 shared == fuck you, i'm shared
 so how would that go. i won't share it? i won't write to it? (that's useless
bc of read fences.) anyway
this is intriguing shit. unification is power. Yeah, the idea of having a unifying label makes some sense, but I haven't been able to figure out what it would mean in terms of behavior. Maybe the middle one would be volatile in that the compiler doesn't optimize use of it but doesn't go so far as to bother with fences? But then the middle ground would be like expert mode, which isn't really what you want. Maybe we're good with just shared and unshared. Sean
Aug 01 2008
parent BCS <ao pathlink.com> writes:
Reply to Sean,

 Yeah, the idea of having a unifying label makes some sense, but I
 haven't been able to figure out what it would mean in terms of 
 behavior.
[...]
 Maybe we're good with just shared and unshared.
The only useful middle ground I see is covered by shared + const (one thread wright, many thread read with whatever else it takes to make that work)
Aug 01 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"superdan" wrote
 Steven Schveighoffer Wrote:
 I'm thinking more in the case of functions.  If I have a function foo, 
 and I
 want to pass my shared data version to it, I need to re-implement foo 
 with
 the parameters as being shared.  Imagine a function with several 
 parameters,
 in which you want to pass a combination of shared/unshared.  That's 2^n
 variations you have to write.
but the code there *is* different. there are fence combinations & shit. i guess in such cases you'd need a template.
The issue I see is that it's not as simple as flipping a switch. If I want to use an object as a shared object, it needs to implement that shared interface now. Might as well code a completely different object. And in that case, can't this just be a library solution (i.e. derive from this object if you want shared access)? You'd probably need to bring volatile back :)
 I think at the very least, for this to be palatable, there needs to be
 another modifier that unifies shared and unshared.  Similar to how const
 unifies mutable and invariant.
sounds interesting but i don't get it. we have: invariant == never changes const == i won't change it mutable == fuck you, i'm changing in the shared cases we have: unshared == never seen by 2 threads ? == ? shared == fuck you, i'm shared so how would that go. i won't share it? i won't write to it? (that's useless bc of read fences.) anyway this is intriguing shit. unification is power.
I have no idea what the middle ground is :) I'm just saying that without that middle ground, it's going to feel like I'm writing code specifically for sharing or not sharing, and the shared keyword loses a lot of its meaning as a general type modifier. I can't just slap a shared label on anything because that object needs to be specifically written to be a shared object. And in the case of functions which take those objects or data types as parameters, slapping a shared label on something means I have to use a completely different set of functions, which might not exist. If I have to use a library for some reason or another, I might just be tempted to cast away the shared. I might have no other choice. -Steve
Aug 01 2008
next sibling parent BCS <ao pathlink.com> writes:
Reply to Steven,

 I have no idea what the middle ground is :)  I'm just saying that
 without that middle ground, it's going to feel like I'm writing code
 specifically for sharing or not sharing,
I stand corrected the middle ground is "don't let me do anything where it matters" No cocreate thing would take on this attribute but references with it could be made from either side.
 and the shared keyword loses
 a lot of its meaning as a general type modifier.  I can't just slap a
 shared label on anything because that object needs to be specifically
 written to be a shared object.
 
 And in the case of functions which take those objects or data types as
 parameters, slapping a shared label on something means I have to use a
 completely different set of functions, which might not exist.  If I
 have to use a library for some reason or another, I might just be
 tempted to cast away the shared.  I might have no other choice.
 
 -Steve
 
Aug 01 2008
prev sibling parent JAnderson <ask me.com> writes:
Steven Schveighoffer wrote:
 "superdan" wrote
 Steven Schveighoffer Wrote:
 I'm thinking more in the case of functions.  If I have a function foo, 
 and I
 want to pass my shared data version to it, I need to re-implement foo 
 with
 the parameters as being shared.  Imagine a function with several 
 parameters,
 in which you want to pass a combination of shared/unshared.  That's 2^n
 variations you have to write.
but the code there *is* different. there are fence combinations & shit. i guess in such cases you'd need a template.
The issue I see is that it's not as simple as flipping a switch. If I want to use an object as a shared object, it needs to implement that shared interface now. Might as well code a completely different object. And in that case, can't this just be a library solution (i.e. derive from this object if you want shared access)? You'd probably need to bring volatile back :)
 I think at the very least, for this to be palatable, there needs to be
 another modifier that unifies shared and unshared.  Similar to how const
 unifies mutable and invariant.
sounds interesting but i don't get it. we have: invariant == never changes const == i won't change it mutable == fuck you, i'm changing in the shared cases we have: unshared == never seen by 2 threads ? == ? shared == fuck you, i'm shared so how would that go. i won't share it? i won't write to it? (that's useless bc of read fences.) anyway this is intriguing shit. unification is power.
I have no idea what the middle ground is :) I'm just saying that without that middle ground, it's going to feel like I'm writing code specifically for sharing or not sharing, and the shared keyword loses a lot of its meaning as a general type modifier. I can't just slap a shared label on anything because that object needs to be specifically written to be a shared object. And in the case of functions which take those objects or data types as parameters, slapping a shared label on something means I have to use a completely different set of functions, which might not exist. If I have to use a library for some reason or another, I might just be tempted to cast away the shared. I might have no other choice. -Steve
Hopefully the shared data will be encapsulated such that you communicate with it though some lightweight class that converts the pieces that your sharing into something unshared functions can work with. We might then only need a small set of standard lib functions for shared memory which do mostly shared memory specific stuff. However we'll see how things go I guess. -Joel
Aug 02 2008
prev sibling next sibling parent reply superdan <super dan.org> writes:
Steven Schveighoffer Wrote:

 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 Nearly all global data is assumed to be and treated as if it were 
 unshared. So making unshared the default is the right solution. And 
 frankly, if you're using a lot of global variables, you might want to 
 reevaluate what you're doing. Lots of global variables is the 80's style 
 of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
The idea is that encapsulation is better, and having something shared between everyone violates encapsulation. When you have a global variable 'int x' that everyone can read and write to, and there's a bug, you have the whole program to search for that bug. The principle of encapsulation is that each chunk of data is visible only to the code that needs to see it, and no more.
So if I write: shared int x; As a global variable, how does this help encapsulation? In the current model, if you need shared data, you use global variables. If you don't need shared data, use member or stack variables. My point is that what you will have done is just made the person who wants a global variable write 'shared' in front of it. I don't see how this helps him protect the variable at all. It just seems like you are enforcing something that already can be enforced.
i dun think so. first off it's naive to assume that global == shared. no way jose. almost all use of shared data is with heap allocated objects that several threads mess with. agreed there are good cases to share shit in a global. but that is the fringe case. not the usual case. second if you write shared int x then all loads/stores of x are fence protected. i might talk outta my ass but if i understand walt you can't just say y = x or x = 5. you must call some intrinsic shit, for example y = load(x) and store(x, 5). not sure i like that actually. third, the interesting shit starts when you take x's address. the shared quality of x goes with its type so &x is shared(int)*, not int*. i might again talk outta my ass but it looks like the compiler has info to fence all shit properly.
 (Programming languages started out with everything being global data, and 
 has moved away from that ever since.)
I'm not advocating using global variables over stack or member variables. All I'm saying is that this 'shared/unshared' model doesn't seem to me like it will eliminate the need for threading constructs, or even help with it.
here is where you apply my other message. what seems or not to you is zilch. come with facts. real arguments and shit.
 Yeah, because all us cowboys don't like your kind.  Maybe we need to get 
 us a rope and have a lynchin.  Seriously, how can you say that the 
 current threadding tools are 'uncontrolled' (i.e. wild west)?
Because of the common multithreaded bug http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html for one example. There is no threading tool I'm aware of that can prevent or detect such bugs.
As described on that page, the problem was fixed with JDK 5, and can be solved using the volatile modifier.
and if you forgot to put volatile your plan is fucked right there. i take issue with c++0x and java 5 equally. they suck shitty goat balls. they *allow* you to write correct code. same as the police allows you to climb mt everest. thank you very much assholes. they do nothing to actually help you with that shit. fuck that shit. if i understand d2 you can't have the dclp bug in d2 even if you tried. the way shit works is you can't have a global that's not shared. if it's shared then the compiler makes it fence protected. if it's fence protected you don't have the dclp bug. problem solved.
 I spend lots of time thinking about multithreadded issues, and make sure 
 my software works properly.  I think the level of quality for threadding 
 issues depends on the coder, not the tools.
I believe the tools can make it easier.
I do too. But I don't see this one being that tool.
see comment above.
 In the case of shared/unshared, it's not going to change anything, except 
 now I have to declare things I didn't have to declare before.  I.e. 
 having shared/unshared is going to be just as wild as before.
Why? First of all, unshared data isn't going to have sequential or sync issues, by definition. Already, you've cut the problem domain down by a huge chunk. Next, shared data access will come with fences or sync. That isn't going to guarantee no deadlocks, but it will guarantee sequential consistency, and at the very least will dramatically cut the problem domain down.
Are you saying that there will be an automatic notion by the compiler that implements the fences, or that I have to add them on top? If the former, then I don't remember reading that in the article, and that does sound promising.
i'm also curious. walt?
 Except now instead of the compiler helping you, you have pushed aside 
 that help and said 'I know what I'm doing'.  Oops, back to the wild west 
 :)
If you want the wild west, you have it, if you want compiler help instead, you got it. How is that worse than C++ or Java, where you always have the wild west and no help at all?
What I'm saying is that if you have to cast just to get something working, you have defeated the system. I'm not saying that you are back to the wild west *by choice*, I'm saying you will most likely end up having to do that just to get it to work. I'm thinking of many cases where you have to use old code, or old libraries that don't have this feature, or code written by someone unaware of the details.
i'd rather break old code than have the shitty model of today. and code written by someone unaware of threading details? you gotta be kidding. i'd erase that code in a second.
 True, but having it happen implicitly is even worse, because there's no 
 indication that it is happening.
dmd mycode.d Error: when calling foo(shared int *), cannot pass int * edit mycode.d, cast to shared int * OK, now it works :) Probably without any problems, because the compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread! But the result is, we're back to the same model as before. And now I have to cast everything. Annoying.
Non-shared can be implicitly cast to shared, as that is always safe. Just not the other way.
How is that possible? shared int *x; void foo(shared int *y) { x = y; } int *x2; void bar() { foo(x2); } After calling bar, isn't x2 now both shared (as x) and unshared at the same time? I think you need casts for both ways.
looks like walt has a problem in his hands :))
 I think shared/unshared is analogous to mutable/invariant.  There is no 
 implicit cast.
looks the same to me too.
 Please let me decide whether I'm far better off.
Ok. D offers both - and for the guy maintaining your code, there'll at least be clear indications of where to look for the source of elusive threading bugs.
All I was saying with that comment is the notion that 'Walter knows best' is not a convincing argument.
"steven schveighoffer seems to feel differently" doesn't help either.
 Optlink currently has a threading bug in it. I have no idea where to look 
 for it in the source code.
Threading problems are very difficult to find. I don't think the shared/unshared model will help with that, especially since most likely you will have to break it to get things working.
what things would you need to break to get things working.
 I generally can only find multithreading issues with lots of logging, and 
 running through potentially offending code in my head.
and that disables d2's premise how.
 I think that this idea has potential, and could possibly lead to something 
 that is helpful.  The thinking is in the right direction.  But I'm not 
 convinced that this incarnation will be helpful.  I'd have to see examples 
 of how this would be useful to understand it better.
 
 And please PLEASE make it backwards compatible.  I don't see any reason why 
 it must be shared that is the tagged value.
i think you have a basic contradiction here. backward is shit. you just said it. to debug mt shit you need to log and rack your brains and shit. then without missing a beat you go you want to keep all that shit. shit man. if shared is only one iota better i'm all for breaking with the past. the past is a fucking world of pain. let's not forget that.
Aug 01 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from superdan (super dan.org)'s article
 Steven Schveighoffer Wrote:
 "Walter Bright" wrote
 Non-shared can be implicitly cast to shared, as that is always safe. Just
 not the other way.
How is that possible? shared int *x; void foo(shared int *y) { x = y; } int *x2; void bar() { foo(x2); } After calling bar, isn't x2 now both shared (as x) and unshared at the same time? I think you need casts for both ways.
looks like walt has a problem in his hands :))
That, or 'shared' applies only to the pointer, not to the value being pointed to. However, given the const system I'd be inclined to think that 'shared' may be transitive, in which case yeah, you've got a problem :-) Sean
Aug 01 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from Sean Kelly (sean invisibleduck.org)'s article
 == Quote from superdan (super dan.org)'s article
 Steven Schveighoffer Wrote:
 "Walter Bright" wrote
 Non-shared can be implicitly cast to shared, as that is always safe. Just
 not the other way.
How is that possible? shared int *x; void foo(shared int *y) { x = y; } int *x2; void bar() { foo(x2); } After calling bar, isn't x2 now both shared (as x) and unshared at the same time? I think you need casts for both ways.
looks like walt has a problem in his hands :))
That, or 'shared' applies only to the pointer, not to the value being pointed to. However, given the const system I'd be inclined to think that 'shared' may be transitive, in which case yeah, you've got a problem :-)
Err... I spoke too soon. Not a problem because then the value would have to be shared as well. I'd guess this is how it will work. Viral, just like const. Sean
Aug 01 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 and if you forgot to put volatile your plan is fucked right there. i
 take issue with c++0x and java 5 equally. they suck shitty goat
 balls. they *allow* you to write correct code. same as the police
 allows you to climb mt everest.
I think you put your finger on the problem. The default behavior of C++ and Java is to do the wrong thing. You have to do extra work to do the right thing. D tries to reverse that by making the default the correct thing, and you have to work extra to screw it up.
 Are you saying that there will be an automatic notion by the
 compiler that implements the fences,
Yes.
Aug 01 2008
prev sibling parent Dee Girl <deegirl noreply.com> writes:
Steven Schveighoffer Wrote:

 shared int *x;
 
 void foo(shared int *y)
 {
     x = y;
 }
 
 int *x2;
 
 void bar()
 {
     foo(x2);
 }
 
 After calling bar, isn't x2 now both shared (as x) and unshared at the same 
 time?  I think you need casts for both ways.
 
 I think shared/unshared is analogous to mutable/invariant.  There is no 
 implicit cast.
Agree with Steve. There should not be easy casting of pointers. i think cast from not shared int to shared int is good. but int* to shared int* is not good. exactly like with invariant. The new model is very interesting! Good Walter I hoped you have a clever solution like invariant and it looks that you have ^_^. Thank you, Dee Girl
Aug 01 2008
prev sibling next sibling parent reply JAnderson <ask me.com> writes:
Steven Schveighoffer wrote:
<Snip>
 dmd mycode.d
 Error: when calling foo(shared int *), cannot pass int *

 edit mycode.d, cast to shared int *

 OK, now it works :)   Probably without any problems, because the 
compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread!
 But the result is, we're back to the same model as before.  And now I 
have to cast everything. Annoying. <Snip> The idea behind compile-time checking like this is that you can quickly identify errors. If someone writes something in a lib you use that is not share safe, you'll know right of the bat. What you want to do with encapsulation is isolate problems at the point at which it occurs, not 5 or 10 classes/functions away when the side effect finally causes weird behavior. With a shared policy you'd be able to encapsulate all shared data to just the parts of the program that use it. That way you have only small set of places to figure out what went wrong. Furthermore it provides a consistent documentation about how a particular object can be used. For example if someone suddenly decides that one of their functions can only work with sharable memory now and your using a non-shared object with it, the compiler will out you when you upgrade that new api and try to compile. If you can't create a shared object or invariant to pass to that function then you dam well better know what your doing. -Joel
Jul 31 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"JAnderson" wrote
 Steven Schveighoffer wrote:
 <Snip>
 dmd mycode.d
 Error: when calling foo(shared int *), cannot pass int *

 edit mycode.d, cast to shared int *

 OK, now it works :)   Probably without any problems, because the
compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread!
 But the result is, we're back to the same model as before.  And now I
have to cast everything. Annoying. <Snip> The idea behind compile-time checking like this is that you can quickly identify errors. If someone writes something in a lib you use that is not share safe, you'll know right of the bat.
I believe the direction that this is heading is promising, but my concern is that it actually won't be helpful as currently described. Because I don't think you can implicitly cast shared to unshared and vice versa, you will need to populate your code with casts wherever you cross the boundaries. If this is a lot, then you will end up creating too much noise to be able to find the problems. This model seems equivalent to having mutable and invariant, but not const (the link between). -Steve
Aug 01 2008
prev sibling parent reply superdan <super dan.org> writes:
Steven Schveighoffer Wrote:

 "Walter Bright" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data.
Nearly all global data is assumed to be and treated as if it were unshared. So making unshared the default is the right solution. And frankly, if you're using a lot of global variables, you might want to reevaluate what you're doing. Lots of global variables is the 80's style of programming :-)
I have no idea where you came up with this. To me global means shared. Global means the world can see it, meaning that it's shared between all. Even VB.net uses 'Shared' as the keyword to mean 'global'
 I would hazard to guess that adopting this would cause a larger rift than 
 const.
Perhaps. But the alternative is the current wild west approach to multithreaded programming. With the proliferation of multicore computers, the era where this is acceptable is coming to an end.
Yeah, because all us cowboys don't like your kind. Maybe we need to get us a rope and have a lynchin. Seriously, how can you say that the current threadding tools are 'uncontrolled' (i.e. wild west)? I spend lots of time thinking about multithreadded issues, and make sure my software works properly. I think the level of quality for threadding issues depends on the coder, not the tools. In the case of shared/unshared, it's not going to change anything, except now I have to declare things I didn't have to declare before. I.e. having shared/unshared is going to be just as wild as before. I may be wrong, and this shared/unshared thing will be really great for people. But I think it needs a lot of work before it's helpful. In its current incarnation, I'll call it the 'shared wild west' approach :P
 Second, the fact that you can't implicitly cast shared to unshared and 
 vice versa.  It's going to make communication between both 'worlds' very 
 error prone, as you will be required to cast for any call from one to the 
 other.
I think the reverse is true. Moving data between those worlds is dangerous and needs to be carefully vetted, so requiring an explicit cast will reduce the chance of this happening unintentionally.
Except now instead of the compiler helping you, you have pushed aside that help and said 'I know what I'm doing'. Oops, back to the wild west :)
 People will do this just to get their code to work, without thinking 
 about the consequences.
True, but having it happen implicitly is even worse, because there's no indication that it is happening.
dmd mycode.d Error: when calling foo(shared int *), cannot pass int * edit mycode.d, cast to shared int * OK, now it works :) Probably without any problems, because the compiler has no idea whether I'm going to change it in another thread. Hell, I might not even HAVE more than one thread! But the result is, we're back to the same model as before. And now I have to cast everything. Annoying.
 Even those that do think about the consequences, can't have the compiler 
 statically check the cast in either direction, so once you cast, you lose 
 all the benefit.
But still, you're far better off than the current wild west approach where everything is implicitly shared with no protection whatsoever. The popular double checked locking bug will be impossible to code in D without stuffing in explicit casts. The casts will be a red flag that the programmer is making a mistake.
Please let me decide whether I'm far better off. I don't need protection from stuff that doesn't matter. I will still have to lock shared data, and still have to cast to get things to work, so I'm not better off. You can't tell me otherwise, because all this stuff is a figment of your imagination. You have no proof. Until you can show me that I'm better off with an actual example, then I believe we both are equally right :) -Steve
you may as well be equally right. or even more right, as you usually are. sure you are a great hacker who knows threads in and out, as "you spend a lot of time thinking about multithreaded issues". i'm impressed. i do suggest you run a lil experiment one day tho. google for walter bright. figure out what kinds of shit he's done. google for bartosz milewski. figure out for what kinds of shit he's done. google for andrei alexanderescu. figure out for what kinds of shit he's done. then google for steven schveighoffer. unless sure enough you are hans boehm in disguise. then ask yourself. "is my big mouth going to make up for all this?"
Jul 31 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"superdan" wrote
 you may as well be equally right. or even more right, as you usually are. 
 sure you are a great hacker who knows threads in and out, as "you spend a 
 lot of time thinking about multithreaded issues". i'm impressed. i do 
 suggest you run a lil experiment one day tho. google for walter bright. 
 figure out what kinds of shit he's done. google for bartosz milewski. 
 figure out for what kinds of shit he's done. google for andrei 
 alexanderescu. figure out for what kinds of shit he's done. then google 
 for steven schveighoffer. unless sure enough you are hans boehm in 
 disguise. then ask yourself. "is my big mouth going to make up for all 
 this?"
Just because I'm not published all over google doesn't mean I don't know anything. Your artistic use of the english language combined with bullying tactics doesn't really phase me, as I care nothing about ego. So go right ahead and bitch about what I don't know :) Last I heard, this is a public forum, and I'm free to question Walter and his team as much as I want. I can't believe you pulled the "do you know who I am" card for Walter :) What do I get if I google for superdan? http://www.youtube.com/watch?v=uLLk42PcM9I -Steve
Aug 01 2008
parent reply superdan <super dan.org> writes:
Steven Schveighoffer Wrote:

 "superdan" wrote
 you may as well be equally right. or even more right, as you usually are. 
 sure you are a great hacker who knows threads in and out, as "you spend a 
 lot of time thinking about multithreaded issues". i'm impressed. i do 
 suggest you run a lil experiment one day tho. google for walter bright. 
 figure out what kinds of shit he's done. google for bartosz milewski. 
 figure out for what kinds of shit he's done. google for andrei 
 alexanderescu. figure out for what kinds of shit he's done. then google 
 for steven schveighoffer. unless sure enough you are hans boehm in 
 disguise. then ask yourself. "is my big mouth going to make up for all 
 this?"
Just because I'm not published all over google doesn't mean I don't know anything. Your artistic use of the english language combined with bullying tactics doesn't really phase me, as I care nothing about ego. So go right ahead and bitch about what I don't know :) Last I heard, this is a public forum, and I'm free to question Walter and his team as much as I want. I can't believe you pulled the "do you know who I am" card for Walter :)
thanks for keeping ur cool. really appreciate that. my intent was not to bully you and shit. this is programming. it's not entomology. anybody who's somebody in programming *is* on the web somewhere for the web is nerdworld. some participation to an open source project. some blog. some article they've written. that's what i see all around. but i still agree. sometimes you can know your shit without being published. you work for nasa, cia, or some secretive hedge fund. or you just don't like sharing shit. no problem. but without a track record you must come with real good *factual* shit to be credible. not "i spend a lot of time thinking about this shit". not what you believe. without a proven track record nobody gives a shit on how you spend your nights or on what you believe. so as long as you stick to facts u should be in good shape. if you come with "my opinion is" shit then you should understand nobody will give a shit. in fact they will give a negative shit because that further fucks your credibility. as an example of good factual shit is your point that nonshared -> shared should not be implicit. now you're talking. i'll think about that shit too. insofar as this being a public forum. i'm a prime abuser of that with my shitfucking and shit. but that is nothing compared to the technical abuse this forum has seen and still does. if that goes down i'd be happy to get my shitfucking shit down too.
 What do I get if I google for superdan?
 
 http://www.youtube.com/watch?v=uLLk42PcM9I
 
 -Steve 
sweet :)
Aug 01 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"superdan" wrote
 Steven Schveighoffer Wrote:

 "superdan" wrote
 you may as well be equally right. or even more right, as you usually 
 are.
 sure you are a great hacker who knows threads in and out, as "you spend 
 a
 lot of time thinking about multithreaded issues". i'm impressed. i do
 suggest you run a lil experiment one day tho. google for walter bright.
 figure out what kinds of shit he's done. google for bartosz milewski.
 figure out for what kinds of shit he's done. google for andrei
 alexanderescu. figure out for what kinds of shit he's done. then google
 for steven schveighoffer. unless sure enough you are hans boehm in
 disguise. then ask yourself. "is my big mouth going to make up for all
 this?"
Just because I'm not published all over google doesn't mean I don't know anything. Your artistic use of the english language combined with bullying tactics doesn't really phase me, as I care nothing about ego. So go right ahead and bitch about what I don't know :) Last I heard, this is a public forum, and I'm free to question Walter and his team as much as I want. I can't believe you pulled the "do you know who I am" card for Walter :)
thanks for keeping ur cool. really appreciate that. my intent was not to bully you and shit. this is programming. it's not entomology. anybody who's somebody in programming *is* on the web somewhere for the web is nerdworld. some participation to an open source project. some blog. some article they've written. that's what i see all around.
I probably have more hits under schveiguy than Steven Schveighoffer. But I don't really write articles. I wrote one for topcoder when I was into that (about threading coincidentally).
 but i still agree. sometimes you can know your shit without being 
 published. you work for nasa, cia, or some secretive hedge fund. or you 
 just don't like sharing shit. no problem. but without a track record you 
 must come with real good *factual* shit to be credible. not "i spend a lot 
 of time thinking about this shit". not what you believe. without a proven 
 track record nobody gives a shit on how you spend your nights or on what 
 you believe.
What I meant by that is, I think possibly the only solution for multithreadded issues is careful planning, training, and experience. In otherwords, my threading code works because I pay careful attention to the threading details. It might be impossible for a technical solution to exist to prevent Joe Newb programmer from making threading mistakes.
 so as long as you stick to facts u should be in good shape. if you come 
 with "my opinion is" shit then you should understand nobody will give a 
 shit. in fact they will give a negative shit because that further fucks 
 your credibility.
You don't have to believe me. Nobody has to believe me. The fact that I stated my opinion is good enough for me. If I turn out to be right, then people might listen to me next time. If I turn out to be wrong, then it still won't stop me from stating my opinion on the next issue. Mind, I can't say anything about facts because I don't have any. I'm very careful to state things in terms of what "I think", and "my opinion". I don't have any more facts than Walter and company to know whether this concept will be useful. All I can say is what I think might happen (as is all Walter can say too). If it turns out to be the best thing since transitive const, then I'm all for it. Remember that Walter and company had several iterations before they got that right. I think that will probably be the case here too.
 insofar as this being a public forum. i'm a prime abuser of that with my 
 shitfucking and shit. but that is nothing compared to the technical abuse 
 this
forum has seen and still does. if that goes down i'd be happy to get my shitfucking shit down too. I don't know what 'shitfucking' is, but it sounds very unpleasant :) -Steve
Aug 01 2008
parent reply superdan <super dan.org> writes:
Steven Schveighoffer Wrote:

 "superdan" wrote
 Steven Schveighoffer Wrote:

 "superdan" wrote
 you may as well be equally right. or even more right, as you usually 
 are.
 sure you are a great hacker who knows threads in and out, as "you spend 
 a
 lot of time thinking about multithreaded issues". i'm impressed. i do
 suggest you run a lil experiment one day tho. google for walter bright.
 figure out what kinds of shit he's done. google for bartosz milewski.
 figure out for what kinds of shit he's done. google for andrei
 alexanderescu. figure out for what kinds of shit he's done. then google
 for steven schveighoffer. unless sure enough you are hans boehm in
 disguise. then ask yourself. "is my big mouth going to make up for all
 this?"
Just because I'm not published all over google doesn't mean I don't know anything. Your artistic use of the english language combined with bullying tactics doesn't really phase me, as I care nothing about ego. So go right ahead and bitch about what I don't know :) Last I heard, this is a public forum, and I'm free to question Walter and his team as much as I want. I can't believe you pulled the "do you know who I am" card for Walter :)
thanks for keeping ur cool. really appreciate that. my intent was not to bully you and shit. this is programming. it's not entomology. anybody who's somebody in programming *is* on the web somewhere for the web is nerdworld. some participation to an open source project. some blog. some article they've written. that's what i see all around.
I probably have more hits under schveiguy than Steven Schveighoffer. But I don't really write articles. I wrote one for topcoder when I was into that (about threading coincidentally).
now yer talking. keep on doing that.
 but i still agree. sometimes you can know your shit without being 
 published. you work for nasa, cia, or some secretive hedge fund. or you 
 just don't like sharing shit. no problem. but without a track record you 
 must come with real good *factual* shit to be credible. not "i spend a lot 
 of time thinking about this shit". not what you believe. without a proven 
 track record nobody gives a shit on how you spend your nights or on what 
 you believe.
What I meant by that is, I think possibly the only solution for multithreadded issues is careful planning, training, and experience. In otherwords, my threading code works because I pay careful attention to the threading details. It might be impossible for a technical solution to exist to prevent Joe Newb programmer from making threading mistakes.
and you're implying that it can't be done any better. you know, if everybody thought like you there'd be no progress. i read napoleon's biography a while ago. one smart motherfucker that was. he really could do two things at the same time. i could only go as far as chew gum and fart. anyway there was this general of his. forgot his name. call him general mofo. so at austerlitz napoleon says let's do this and that. mofo comes back: "if i were you i'd do this and that". napoleon says: "that's why you are mofo and i'm fucking napoleon". i might've added a word in the quote somewhere :) i was working at intel. there's this layout program that would take forfuckingever on a design i'd given it. so during lunch i'm like, "what a fucking piece of shit this layout algo is." and a new coworker smiles and says "i know. i designed it." he was kind enough to explain what problems he'd overcome. like heuristics on np complete shit. i don't even know exactly what that is. sure enough, when it's done his program did a layout i couldn't imagine in a brazillion years. these guys operate at a different level. and as far as walter or bartosz are concerned i'm a pathetic loser. at least i'm glad when i can appreciate a good idea if i see it. and the more it goes about how i feel it can't be done, the better the idea. at least with time i learned not to come all cocky and shit with stuff i don't grok.
 so as long as you stick to facts u should be in good shape. if you come 
 with "my opinion is" shit then you should understand nobody will give a 
 shit. in fact they will give a negative shit because that further fucks 
 your credibility.
You don't have to believe me. Nobody has to believe me. The fact that I stated my opinion is good enough for me. If I turn out to be right, then people might listen to me next time. If I turn out to be wrong, then it still won't stop me from stating my opinion on the next issue.
doesn't work that way dewd. it's like crying wolf whenever you feel it in your urine. open the cabbage patches. then the mind. then the piehole. that's how it works. i read this thread stuff yesterday a few times. my first reaction was it's useless. second reaction was it's restrictive as shit. third read i thought they might be up to something. and it was the interaction with invariant that brought it all home for me. most importantly i didn't shout my piehole around after the first read.
  Mind, I 
 can't say anything about facts because I don't have any.  I'm very careful 
 to state things in terms of what "I think", and "my opinion".  I don't have 
 any more facts than Walter and company to know whether this concept will be 
 useful.  All I can say is what I think might happen (as is all Walter can 
 say too).  If it turns out to be the best thing since transitive const, then 
 I'm all for it.  Remember that Walter and company had several iterations 
 before they got that right.  I think that will probably be the case here 
 too.
my point is you (and me too) have less facts, less experience, less smarts, and less intuition than walt & co. if we tell them about a mistake, fine. but if we go with "i feel shit" that's not progress. it's good you compare with the const shit. that's the most fucking awesome thing about d2. if you asked me before i would've told you nobody can pull that shit and live. more over. walt has got a shitstorm the size of fucking china when he got it wrong. if i were walt i would've given up. but that's why walt is walt he kept at it and pushed the shit through. what pisses me off is that to this day people still bitch about const while refusing to actually understand it. it's not even hard. first understand. then bitch.
Aug 01 2008
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 i read napoleon's biography a while ago. one smart motherfucker that
 was. he really could do two things at the same time. i could only go
 as far as chew gum and fart. anyway there was this general of his.
 forgot his name. call him general mofo. so at austerlitz napoleon
 says let's do this and that. mofo comes back: "if i were you i'd do
 this and that". napoleon says: "that's why you are mofo and i'm
 fucking napoleon". i might've added a word in the quote somewhere :)
Do you believe that General McAuliffe really said "nuts" at the Battle of the Bulge? I don't. <g>
Aug 01 2008
parent reply superdan <super dan.org> writes:
Walter Bright Wrote:

 superdan wrote:
 i read napoleon's biography a while ago. one smart motherfucker that
 was. he really could do two things at the same time. i could only go
 as far as chew gum and fart. anyway there was this general of his.
 forgot his name. call him general mofo. so at austerlitz napoleon
 says let's do this and that. mofo comes back: "if i were you i'd do
 this and that". napoleon says: "that's why you are mofo and i'm
 fucking napoleon". i might've added a word in the quote somewhere :)
Do you believe that General McAuliffe really said "nuts" at the Battle of the Bulge? I don't. <g>
let's see. four-words expletive too strong for the american public. sure it was "poop" :) can't think of bastogne without thinking of BoB. what an awesome movie that is.
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
superdan wrote:
 Do you believe that General McAuliffe really said "nuts" at the Battle 
 of the Bulge? I don't. <g> 

let's see. four-words expletive too strong for the american public. sure it was "poop" :) can't think of bastogne without thinking of BoB. what an awesome movie that is.
My father met the man and asked him. The actual word rhymes with "spit". I'm amused by the people who think a GI would really use the word "nuts".
Aug 01 2008
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"superdan" wrote
 Steven Schveighoffer Wrote:

 "superdan" wrote
 but i still agree. sometimes you can know your shit without being
 published. you work for nasa, cia, or some secretive hedge fund. or you
 just don't like sharing shit. no problem. but without a track record 
 you
 must come with real good *factual* shit to be credible. not "i spend a 
 lot
 of time thinking about this shit". not what you believe. without a 
 proven
 track record nobody gives a shit on how you spend your nights or on 
 what
 you believe.
What I meant by that is, I think possibly the only solution for multithreadded issues is careful planning, training, and experience. In otherwords, my threading code works because I pay careful attention to the threading details. It might be impossible for a technical solution to exist to prevent Joe Newb programmer from making threading mistakes.
and you're implying that it can't be done any better. you know, if everybody thought like you there'd be no progress.
I'm not saying that we shouldn't try. I'm just saying it *might* be impossible. I encourage Walter to solve it, but I can't see how this solution does it. Look into NP-complete. It's a set of problems that nobody can write a program to solve it (efficiently anyways). First one I ever heard of is the traveling salesman problem: http://en.wikipedia.org/wiki/Traveling_salesman_problem
 so as long as you stick to facts u should be in good shape. if you come
 with "my opinion is" shit then you should understand nobody will give a
 shit. in fact they will give a negative shit because that further fucks
 your credibility.
You don't have to believe me. Nobody has to believe me. The fact that I stated my opinion is good enough for me. If I turn out to be right, then people might listen to me next time. If I turn out to be wrong, then it still won't stop me from stating my opinion on the next issue.
doesn't work that way dewd. it's like crying wolf whenever you feel it in your urine. open the cabbage patches. then the mind. then the piehole. that's how it works. i read this thread stuff yesterday a few times. my first reaction was it's useless. second reaction was it's restrictive as shit. third read i thought they might be up to something. and it was the interaction with invariant that brought it all home for me. most importantly i didn't shout my piehole around after the first read.
I admit that I already knew this shared/unshared was coming :) So I already had thought about it over a month ago, but I wasn't allowed to talk about it on the NG. But I'm a little disappointed that it's no different than the version I saw before... Bottom line, I did think about it before posting. Quite a bit.
  Mind, I
 can't say anything about facts because I don't have any.  I'm very 
 careful
 to state things in terms of what "I think", and "my opinion".  I don't 
 have
 any more facts than Walter and company to know whether this concept will 
 be
 useful.  All I can say is what I think might happen (as is all Walter can
 say too).  If it turns out to be the best thing since transitive const, 
 then
 I'm all for it.  Remember that Walter and company had several iterations
 before they got that right.  I think that will probably be the case here
 too.
my point is you (and me too) have less facts, less experience, less smarts, and less intuition than walt & co. if we tell them about a mistake, fine. but if we go with "i feel shit" that's not progress.
Hey, don't listen to me. Nobody has to do what I say based on a feeling. But I'm sure as hell not going to accept that if Walter feels good about it, it must be right, any more than you won't accept what I say because I don't feel good about it. I need proof. And the burden of proof is on Walter. I've already written multithreadded programs with the current D system, and they work. You need to convince me that this new way will work more than just "Trust me, you'll be better off".
 it's good you compare with the const shit. that's the most fucking awesome 
 thing about d2. if you asked me before i would've told you nobody can pull 
 that shit and live. more over. walt has got a shitstorm the size of 
 fucking china when he got it wrong. if i were walt i would've given up. 
 but that's why walt is walt he kept at it and pushed the shit through. 
 what pisses me off is that to this day people still bitch about const 
 while refusing to actually understand it. it's not even hard. first 
 understand. then bitch.
I am one of those that fully understands the const system, and I still think it is missing some pieces :) Every proposal I've made to fill in those pieces on the NG and to Andrei directly ultimately results in a response like "yes that looks like a sound idea, and would work, but we *feel* that it would make people like const less, so we're not going to implement it." I love a lot of what Walter and Andrei have done, but when ideas are shot down due to a perception of what might happen in the future, it seems to be based a lot less on fact than I would like. -Steve
Aug 01 2008
prev sibling next sibling parent reply JAnderson <ask me.com> writes:
Steven Schveighoffer wrote:
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data. I would hazard to guess that adopting this would cause a larger rift than const.
<Snip> As far as radical changes to the language breaking existing code, if Walter maintained that approach D would never beable to make radical and correct improvements (rather then half-work rounds). We would end up with C++. This is why we have D 1 and 2. D 2 is still the experimental branch. Yes it makes radical changes however D might never be able to provide better multi-threading support if it can't make breaking changes. My option is that the experimental branch of D should be correct first and backwoods compatible second. Having said that. I don't think this shared approach should be added to the language until const is sorted because that should provide a kinda proof of concept for the syntactics of shared memory. <Snip>
 
 -Steve 
 
 
Jul 31 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"JAnderson" wrote
 Steven Schveighoffer wrote:
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data. I would hazard to guess that adopting this would cause a larger rift than const.
<Snip> As far as radical changes to the language breaking existing code, if Walter maintained that approach D would never beable to make radical and correct improvements (rather then half-work rounds). We would end up with C++. This is why we have D 1 and 2. D 2 is still the experimental branch. Yes it makes radical changes however D might never be able to provide better multi-threading support if it can't make breaking changes.
So should people wait to write libraries until all this is fleshed out? I mean, there is already a pretty significant code base that assumes shared is the default. When this ever gets around to being implemented (and released), how much work will it be to rewrite all code to either use a new model, or put a shared tag on every variable? It seems to me the logical approach is to assume shared and tag things as unshared.
 My option is that the experimental branch of D should be correct first and 
 backwoods compatible second.
That is a great recipe for the forking of D :) I'm not saying that breaking changes should be unacceptable, I'm just saying that there better be a really compelling reason to break things. I believe Walter's view of "wild west" programming is completely off target. Many good multithreadded applications exist today, without the aid of this shared/unshared view. I don't see how having this is going to magically solve any threadding issues. If anything it's going to just pop up as an annoying obstacle that is frequently bypassed with casts, making the system useless anyways. I don't know if this can be shown until the idea moves from theory to practice, so maybe we'll just have to wait and see. This could be a stepping stone to a really great system, just like the first const incarnations were awful, but the one we have now (save a few missing pieces) is pretty good. Just my opinion. -Steve
Jul 31 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s article
 "JAnderson" wrote
 My option is that the experimental branch of D should be correct first and
 backwoods compatible second.
That is a great recipe for the forking of D :) I'm not saying that breaking changes should be unacceptable, I'm just saying that there better be a really compelling reason to break things.
libd forked the language and is far better for it. Tango has avoided this route because our primary goal is to provide a library for D. This seems to have turned out to be "provide a library for D 1.0" however, given the lack of support for certain programming methodologies in D 2.0 that Tango uses pervasively, as you're no doubt aware :-) This leaves Tango in a bit of a pickle, since it means either changing Tango or forking D if we ever want to move past D 1.0.
 I believe Walter's view of "wild west" programming is completely off target.
 Many good multithreadded applications exist today, without the aid of this
 shared/unshared view.  I don't see how having this is going to magically
 solve any threadding issues.  If anything it's going to just pop up as an
 annoying obstacle that is frequently bypassed with casts, making the system
 useless anyways.  I don't know if this can be shown until the idea moves
 from theory to practice, so maybe we'll just have to wait and see.  This
 could be a stepping stone to a really great system, just like the first
 const incarnations were awful, but the one we have now (save a few missing
 pieces) is pretty good.
Systems programming is the low-down dirtiest part of the Wild West, too. It's a realm where programmers do all sorts of things that a general applications programmer would be canned for, because it's necessary and because they *do* know what they're doing. I am very much concerned that the "future of D" is as a general applications language and that its systems language roots will be left to rot. And who needs another applications language, anyway? The world has a million of them. Sean
Jul 31 2008
parent reply bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:
 I am very much concerned that the "future of D" is
 as a general applications language and that its systems language roots will
 be left to rot.  And who needs another applications language, anyway?  The
 world has a million of them.
I think D is already partially unfit for being a system language, the runtime memory footprint is large; here it's compared with Free Pascal: http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=dlang&lang2=fpascal The GC can be disabled, but you have to carry it around in the executable anyway. The size of the executables produced by DMD is large compared to the exes you obtain from stripped C. At the moment you can't run such things on sytems with little RAM, as you can do with C. Regarding the hard real time systems, I think people there are scared of a GC (even if in practice it's not a problem). So at the moment there are many things you can do with C that are a problem to do with D. Bye, bearophile
Jul 31 2008
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 Sean Kelly:
 I am very much concerned that the "future of D" is
 as a general applications language and that its systems language roots will
 be left to rot.  And who needs another applications language, anyway?  The
 world has a million of them.
I think D is already partially unfit for being a system language, the runtime memory footprint is large; here it's
compared with Free Pascal:
 http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=dlang&lang2=fpascal
Agreed. This is largely related to the generated TypeInfo, and is somewhat annoying.
 The GC can be disabled, but you have to carry it around in the executable
anyway. The size of the executables
produced by DMD is large compared to the exes you obtain from stripped C. At the moment you can't run such things on sytems with little RAM, as you can do with C. It's actually possible to create a D application that doesn't have a GC at all. Tango even supports this out of the box. The downside is that some language features rely on the existence of a GC and won't work properly without one. AAs are one example, and string concatenation is another. However, a sufficiently diligent programmer could just not use these features, or the runtime could be modified to explicitly support a GC-less application by making different assumptions about what happens to discarded memory, etc.
 Regarding the hard real time systems, I think people there are scared of a GC
(even if in practice it's not a problem).
So at the moment there are many things you can do with C that are a problem to do with D. There are soft real-time GCs. In fact, I believe there are hard real-time GCs as well--the Metronome project at IBM springs to mind. I would love to see such a GC for D, but I don't have the time and am also not certain that it's possible to make a hard real-time conservative GC (which D currently requires). I would be inclined to think that such a GC would be incremental and thus require more comprehensive type info, but I haven't given the topic enough thought to be certain about that. All that said, I believe it's entirely possible to write performance-critical code in D so long as the programmer is careful about memory allocation. And as Walter has said before, because even malloc is not time-constrained the same goes for any use of dynamic memory--GCs just magnify the issue. Server apps in Tango, for example, don't allocate any memory at all once initialization is complete. This is why they tend to be so blisteringly fast. It's also why Tango is designed the way it is--not always super-convenient for run of the mill apps programming, but quite scalable for high-end work. By contrast, I'd argue that Phobos is the opposite. Sean
Jul 31 2008
next sibling parent reply superdan <super dan.org> writes:
Sean Kelly Wrote:

 All that said, I believe it's entirely possible to write performance-critical
code in D so long as the
 programmer is careful about memory allocation.  And as Walter has said before,
because even
 malloc is not time-constrained the same goes for any use of dynamic
memory--GCs just magnify
 the issue.  Server apps in Tango, for example, don't allocate any memory at
all once initialization
 is complete.  This is why they tend to be so blisteringly fast.  It's also why
Tango is designed the
 way it is--not always super-convenient for run of the mill apps programming,
but quite scalable
 for high-end work.  By contrast, I'd argue that Phobos is the opposite.
i agree. std.algorithm i sleep with under my pillow. but std.xml. what a sick piece of shit that is. if they tried to make it slow on purpose they couldn't have succeeded better. std.xml must go.
Jul 31 2008
parent reply downs <default_357-line yahoo.de> writes:
superdan wrote:
 Sean Kelly Wrote:
 
 All that said, I believe it's entirely possible to write performance-critical
code in D so long as the
 programmer is careful about memory allocation.  And as Walter has said before,
because even
 malloc is not time-constrained the same goes for any use of dynamic
memory--GCs just magnify
 the issue.  Server apps in Tango, for example, don't allocate any memory at
all once initialization
 is complete.  This is why they tend to be so blisteringly fast.  It's also why
Tango is designed the
 way it is--not always super-convenient for run of the mill apps programming,
but quite scalable
 for high-end work.  By contrast, I'd argue that Phobos is the opposite.
i agree. std.algorithm i sleep with under my pillow. but std.xml. what a sick piece of shit that is. if they tried to make it slow on purpose they couldn't have succeeded better. std.xml must go.
Heh. Want to have some fun, take a look at std.zip. Then realize that, unless you unpack every member every time, the members you didn't unpack will still have their compressed data overwritten by a compressed version of the expanded data (which is ""). Then weep. --downs, immensely glad the zip archive he noticed this on was backed up in SVN.
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 Heh. Want to have some fun, take a look at std.zip.
 
 Then realize that, unless you unpack every member every time, the
 members you didn't unpack will still have their compressed data
 overwritten by a compressed version of the expanded data (which is
 "").
 
 Then weep.
 
 --downs, immensely glad the zip archive he noticed this on was backed
 up in SVN.
Please file this with bugzilla, or even better, a patch!
Aug 01 2008
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:
 All that said, I believe it's entirely possible to write performance-critical
code in D so long as the
 programmer is careful about memory allocation.
I agree, in many D programs I have found that avoiding memory allocations can speed up the code 5-15 times. You can see the last time I have seen that in this thread: But Java HotSpot shows that a good GC can make fast enough many programs that allocate memory often (but they often need 4-10 times more RAM). Bye, bearophile
Jul 31 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 All that said, I believe it's entirely possible to write performance-critical
code in D so long as the
 programmer is careful about memory allocation.  And as Walter has said before,
because even
 malloc is not time-constrained the same goes for any use of dynamic
memory--GCs just magnify
 the issue.  Server apps in Tango, for example, don't allocate any memory at
all once initialization
 is complete.  This is why they tend to be so blisteringly fast.  It's also why
Tango is designed the
 way it is--not always super-convenient for run of the mill apps programming,
but quite scalable
 for high-end work.  By contrast, I'd argue that Phobos is the opposite.
I wrote a version of Empire (the game) in D that does no allocation at all. Therefore, the gc never runs and there is never any unbounded delay. The gc is never going to pop up out of nowhere and sink your application. A gc only happens when you request memory from the gc. For the real time constrained section of code, the idea is to pre-allocate all the data you'll need first, then do no allocation within the critical section. In fact, such critical code in C++ does this anyway because there are no bounded time constraints on C++ new either. C malloc has no bound constraints, either.
Jul 31 2008
parent reply JAnderson <ask me.com> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 All that said, I believe it's entirely possible to write 
 performance-critical code in D so long as the
 programmer is careful about memory allocation.  And as Walter has said 
 before, because even
 malloc is not time-constrained the same goes for any use of dynamic 
 memory--GCs just magnify
 the issue.  Server apps in Tango, for example, don't allocate any 
 memory at all once initialization
 is complete.  This is why they tend to be so blisteringly fast.  It's 
 also why Tango is designed the
 way it is--not always super-convenient for run of the mill apps 
 programming, but quite scalable
 for high-end work.  By contrast, I'd argue that Phobos is the opposite.
I wrote a version of Empire (the game) in D that does no allocation at all. Therefore, the gc never runs and there is never any unbounded delay. The gc is never going to pop up out of nowhere and sink your application. A gc only happens when you request memory from the gc. For the real time constrained section of code, the idea is to pre-allocate all the data you'll need first, then do no allocation within the critical section. In fact, such critical code in C++ does this anyway because there are no bounded time constraints on C++ new either. C malloc has no bound constraints, either.
This is true, new in C++ can seriously degrade performance if not manage properly. However calling a couple of 100 smallish news in C++ per frame is quite acceptable and has a infindecimal affect on performance, when working on windows. D however is another kettle of fish. You can't have any allocations during the active part of the game. You have to do it all a load points. Why? Because at some point the memory allocator will runout of free memory and then it will need to clear anything that's unused. Normally this wouldn't be a problem however it takes over a frame to flush; and that leads to a very noticeable stutter. Now I haven't tried realtime programming with allocations in the realtime part for a while so things might have changed however that's how it was the last time I was playing around with that stuff. Also I haven't tried Tangos. Also nedmalloc can give a huge performance boost to windows allocation making it almost as good as preallocations. Sometimes its better due to memory locality which reduce cache misses. The great thing about D's GC though its that other people can implement there own. I hope that when someone comes up with a really good one and it will become part of the main distribution (ie not become another windows malloc mess). -Joel
Jul 31 2008
parent JAnderson <ask me.com> writes:
JAnderson wrote:
 Walter Bright wrote:
 Sean Kelly wrote:
 All that said, I believe it's entirely possible to write 
 performance-critical code in D so long as the
 programmer is careful about memory allocation.  And as Walter has 
 said before, because even
 malloc is not time-constrained the same goes for any use of dynamic 
 memory--GCs just magnify
 the issue.  Server apps in Tango, for example, don't allocate any 
 memory at all once initialization
 is complete.  This is why they tend to be so blisteringly fast.  It's 
 also why Tango is designed the
 way it is--not always super-convenient for run of the mill apps 
 programming, but quite scalable
 for high-end work.  By contrast, I'd argue that Phobos is the opposite.
I wrote a version of Empire (the game) in D that does no allocation at all. Therefore, the gc never runs and there is never any unbounded delay. The gc is never going to pop up out of nowhere and sink your application. A gc only happens when you request memory from the gc. For the real time constrained section of code, the idea is to pre-allocate all the data you'll need first, then do no allocation within the critical section. In fact, such critical code in C++ does this anyway because there are no bounded time constraints on C++ new either. C malloc has no bound constraints, either.
This is true, new in C++ can seriously degrade performance if not manage properly. However calling a couple of 100 smallish news in C++ per frame is quite acceptable and has a infindecimal affect on performance, when working on windows.
I should point out that I'm aware of fragmentation however you can still call new's in either a way that doesn't fragment, or simply rely on paging to fix the problem. If your not creating a program that needs to run longer then a month (ie maybe your game has a maximum time limit of 30 minutes or something) then the problem is even less of an issue. If you are, make sure you understand fragmentation.
 
 D however is another kettle of fish.  You can't have any allocations 
 during the active part of the game.  You have to do it all a load 
 points.  Why? Because at some point the memory allocator will runout of 
 free memory and then it will need to clear anything that's unused. 
 Normally this wouldn't be a problem however it takes over a frame to 
 flush; and that leads to a very noticeable stutter.
 
 Now I haven't tried realtime programming with allocations in the 
 realtime part for a while so things might have changed however that's 
 how it was the last time I was playing around with that stuff.  Also I 
 haven't tried Tangos.
 
 Also nedmalloc can give a huge performance boost to windows allocation 
 making it almost as good as preallocations. Sometimes its better due to 
 memory locality which reduce cache misses.
 
 The great thing about D's GC though its that other people can implement 
 there own.  I hope that when someone comes up with a really good one and 
 it will become part of the main distribution (ie not become another 
 windows malloc mess).
 
 -Joel
Jul 31 2008
prev sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 Sean Kelly:
 I am very much concerned that the "future of D" is
 as a general applications language and that its systems language roots will
 be left to rot.  And who needs another applications language, anyway?  The
 world has a million of them.
I think D is already partially unfit for being a system language, the runtime
memory footprint is large; here it's compared with Free Pascal:

http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=dlang&lang2=fpascal
 The GC can be disabled, but you have to carry it around in the executable
anyway. The size of the executables produced by DMD is large compared to the exes you obtain from stripped C. At the moment you can't run such things on sytems with little RAM, as you can do with C.
 Regarding the hard real time systems, I think people there are scared of a GC
(even if in practice it's not a problem). So at the moment there are many things you can do with C that are a problem to do with D.
 Bye,
 bearophile
A few things: First of all, Pascal is from the Stone Age and therefore has had a chance to be optimized in every way feasible to make it as tight as humanly possible. DMD is a reference implementation of a relatively immature language, and right now the focus is on adding more features and fixing bugs, not on aggressive space optimization. Maybe once the dust settles a little, the GC can optionally be made a shared DLL, or excluded outright if the programmer is going to disable it anyhow, and optimizations can be added to make it more space-efficient. Second: I actually think D is a great application programming language that fills a pretty useful niche. I am a computational biologist, so my needs are basically performance, correctness and ease of use. If I wrote everything in C, C++ or (I almost don't even want to say it) Fortran, I'd never get anything done because these are such crufty old languages that are much more difficult to use than D. shoved down my throat where it makes the least sense, namely small but performance-critical projects. If I used Python or Ruby, the performance penalty would just be ridiculous unless I wrote some parts in C, in which case...uh, I kind of wanted to avoid using old-school, low-level languages. Bottom line is, D gives me most of the ease of use of a high-level dynamic language and most of the performance of C or C++, and for what I do that seems like a very good tradeoff.
Jul 31 2008
next sibling parent downs <default_357-line yahoo.de> writes:
dsimcha wrote:
 Bottom line is, D gives me most of the ease of use of a high-level dynamic
 language and most of the performance of C or C++, and for what I do that seems
 like a very good tradeoff.
Couldn't agree more. --downs
Jul 31 2008
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
 A few things:  First of all, Pascal is from the Stone Age and therefore has
had a
 chance to be optimized in every way feasible to make it as tight as humanly
 possible.
Yet, we're talking about a pretty modern ObjectPascal here, with a syntax quite close to the Delphi one. I have used it, and it's a good language, you can write tons of things with it, and it's way different from the C language, it has many nice modern things, and very little pointers, it's plenty fast, the IDEs are good, etc, but I understand your point and I agree. I know that D is young, etc, and if you follow this group you probably know that I like D.
 Second:  I actually think D is a great application programming language that
fills
 a pretty useful niche.  I am a computational biologist, so my needs are
basically
 performance, correctness and ease of use.
I too use D mostly for bioinformatics, I have introduced it (with Python, well Python first) in my lab that so far has used mostly Perl/Fortran/C. And I too like to use D for such purposes, sometimes Python is too much slow, and I don't want to use Cython much because for me programming in D is much simpler than keeping track of the mad reference counts in Cython programs. (But I think such purposes of D aren't exactly the same you may want from a system language this thread was talking about, you too talk about 'application programming language'). Bye, bearophile
Jul 31 2008
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Steven Schveighoffer" wrote
 "Walter Bright" wrote
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
There are 2 problems I see with this scheme. First, that the default is 'unshared'. This is going to break a lot of existing code, and make peoples lives miserable who do not want to deal with unshared non-stack data. I would hazard to guess that adopting this would cause a larger rift than const.
After thinking about this some more, I realize that this part of my argument is wrong. I was thinking since by default you can share data today, that should be the default. But most of the time, you declare things (global or otherwise) expecting them not to be shared. Shared data is usually wrapped in an object that you can synchronize on. So most existing code should work fine unless that code expects to share data with other threads. That being said, I still see issues with casting and with function calling. -Steve
Aug 01 2008
prev sibling next sibling parent Knud Soerensen <4tuu4k002 sneakemail.com> writes:
Walter Bright wrote:
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
I have also posted it on my new news site http://crowdnews.eu -- Crowdnews.eu - Promote yourself and your friends!
Jul 30 2008
prev sibling next sibling parent reply "Craig Black" <cblack ara.com> writes:
If I understand it correctly, then you are going down the right path with 
this stuff.  IMO, the ultimate goal is a programming language that is 
thread-safe by default, just as a GC language is memory-safe by default.  I 
sounds like you may need to flesh things out quite a bit to attain a 
comprehensive solution for thread safety.  Keep in mind, there should always 
be ways to subvert safety when necessary for performance.

-Craig 
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Craig Black wrote:
 If I understand it correctly, then you are going down the right path with 
 this stuff.  IMO, the ultimate goal is a programming language that is 
 thread-safe by default, just as a GC language is memory-safe by default.
You aren't the first to note the analogy to GC!
 I sounds like you may need to flesh things out quite a bit to attain a 
 comprehensive solution for thread safety.  Keep in mind, there should always 
 be ways to subvert safety when necessary for performance.
Of course - casting a shared type to unshared means subverting any compiler guarantees, just like when const is cast away.
Jul 31 2008
parent superdan <super dan.org> writes:
Walter Bright Wrote:

 Craig Black wrote:
 If I understand it correctly, then you are going down the right path with 
 this stuff.  IMO, the ultimate goal is a programming language that is 
 thread-safe by default, just as a GC language is memory-safe by default.
You aren't the first to note the analogy to GC!
yeh i could swear i read an article about that. was his name grosh or so? interesting shit that was. i finally read bartosz' stuff. the basic idea looks cool. i bet there will be much kinks to work out tho. fwiw perl does similar shit in one of its many attempts at threads. aside from being slow like molasses in the winter the model is clean. problem is perl must duplicate a lot more shit than d has. so things stand good for d. pooling will help a ton too.
Jul 31 2008
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
Sounds like the addition of a thread-local storage class (which I've been asking for since I discovered D), plus some language checking on top of that. I'll admit to being somewhat concerned that the checking aspect will incur an unwanted runtime expense, as I don't believe there's any way at compile-time to detect that a variable is being accessed by multiple threads. One could try to assert that non-shared data may never be used in synchronized blocks, but not all data used in such blocks is actually shared. In short, I'd love a "thread" storage class, as always, and would be curious to see how the rest turns out. It sounds unlikely to work, but who knows. That said, data can be shared in one of two ways: either it may be referenced via a static or global variable or it may be explicitly passed between two threads. The latter case is typically safe because it's deliberate while the former may well not be. Thus, the easiest way to get all this working would be to forbid the use of "static" in a multithreaded app, or add checking to "static" so it acts like "shared." That eliminates the need for a new keyword and makes existing apps all compile correctly by default. The final step would be to require that all static functions either be atomic or contain a "synchronized" statement. Easy to do at compile-time and it would get the job done for the most part. It's too bad we've been unable to talk about any of this offline. We've been considering doing a lot of this sort of thing with Tango for years now but had been avoiding any unnecessary runtime changes in hopes that it would increase the likelihood that the powers that be would get involved. Obviously, that idea failed :-) But I'll take this as implicit permission to have at it, since you seem to be talking along roughly similar lines for D2 anyway. Sean
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 Sounds like the addition of a thread-local storage class (which
 I've been asking for since I discovered D),
It's actually implemented in D 2.0 as the __thread storage class, however it's for testing purposes only.
 plus some language
 checking on top of that.  I'll admit to being somewhat concerned
 that the checking aspect will incur an unwanted runtime expense,
 as I don't believe there's any way at compile-time to detect that
 a variable is being accessed by multiple threads.
It's done statically by the type - a shared type can be accessed by multiple types, an unshared type cannot.
 It's too bad we've been unable to talk about any of this
 offline.  We've been considering doing a lot of this sort
 of thing with Tango for years now but had been avoiding any
 unnecessary runtime changes in hopes that it would increase
 the likelihood that the powers that be would get involved.
 Obviously, that idea failed :-)  But I'll take this as
 implicit permission to have at it, since you seem to be
 talking along roughly similar lines for D2 anyway.
We've been talking about doing it as a static type system, not as a runtime one. Bartosz mentioned that there are ways to do it at runtime, but there are a lot of issues that would need to be worked out for that.
Jul 31 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Sounds like the addition of a thread-local storage class (which
 I've been asking for since I discovered D),
It's actually implemented in D 2.0 as the __thread storage class, however it's for testing purposes only.
Yeah, I saw that. If only it were in D 1.0 :-)
 plus some language
 checking on top of that.  I'll admit to being somewhat concerned
 that the checking aspect will incur an unwanted runtime expense,
 as I don't believe there's any way at compile-time to detect that
 a variable is being accessed by multiple threads.
It's done statically by the type - a shared type can be accessed by multiple types, an unshared type cannot.
What about this: shared ClassA a; void main() { ClassB b = a.getB(); b.mutate(); } I'd imagine the checking will catch common mistakes but not issues like the above? Or will the fact that 'b' is being returned from a require the declaration of 'b' to be shared because the value may be accessed by both ClassA and anything outside ClassA? Sean
Jul 31 2008
next sibling parent reply downs <default_357-line yahoo.de> writes:
Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Sounds like the addition of a thread-local storage class (which
 I've been asking for since I discovered D),
It's actually implemented in D 2.0 as the __thread storage class, however it's for testing purposes only.
Yeah, I saw that. If only it were in D 1.0 :-)
1.0 has tools.threads' TLS!(), so you can use that :) It works under win32 and posix. </tools_ad> --downs
Aug 01 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"downs" <default_357-line yahoo.de> wrote in message 
news:g6ufic$1hj4$2 digitalmars.com...
 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Sounds like the addition of a thread-local storage class (which
 I've been asking for since I discovered D),
It's actually implemented in D 2.0 as the __thread storage class, however it's for testing purposes only.
Yeah, I saw that. If only it were in D 1.0 :-)
1.0 has tools.threads' TLS!(), so you can use that :) It works under win32 and posix. </tools_ad> --downs
You do realize (1) you're advertising to one of the main Tango devs, and (2) Tango already has thread-local storage.
Aug 01 2008
parent downs <default_357-line yahoo.de> writes:
Jarrett Billingsley wrote:
 "downs" <default_357-line yahoo.de> wrote in message 
 news:g6ufic$1hj4$2 digitalmars.com...
 Sean Kelly wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 Sean Kelly wrote:
 Sounds like the addition of a thread-local storage class (which
 I've been asking for since I discovered D),
It's actually implemented in D 2.0 as the __thread storage class, however it's for testing purposes only.
Yeah, I saw that. If only it were in D 1.0 :-)
1.0 has tools.threads' TLS!(), so you can use that :) It works under win32 and posix. </tools_ad> --downs
You do realize (1) you're advertising to one of the main Tango devs, and (2) Tango already has thread-local storage.
Um. Well, yeah, I realize that _now_ :) Sorry for that misunderstanding.
Aug 01 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Sean Kelly wrote:
 What about this:
 
     shared ClassA a;
 
     void main()
     {
         ClassB b = a.getB();
         b.mutate();
     }
 
 I'd imagine the checking will catch common mistakes but not issues
 like the above?  Or will the fact that 'b' is being returned from
 a require the declaration of 'b' to be shared because the value
 may be accessed by both ClassA and anything outside ClassA?
Shared cannot be implicitly cast to unshared. Just like const cannot be implicitly cast to mutable.
Aug 01 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Walter Bright wrote:
 Shared cannot be implicitly cast to unshared. Just like const cannot be 
 implicitly cast to mutable.
But you can implicitly cast unshared to shared, right?
Aug 07 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Russell Lewis" wrote
 Walter Bright wrote:
 Shared cannot be implicitly cast to unshared. Just like const cannot be 
 implicitly cast to mutable.
But you can implicitly cast unshared to shared, right?
No. There is no implicit casting or else you can have data that is shared and unshared at the same time. It will be up to the coder to ensure only one is happening at a time. -Steve
Aug 07 2008
parent reply Russell Lewis <webmaster villagersonline.com> writes:
Steven Schveighoffer wrote:
 "Russell Lewis" wrote
 Walter Bright wrote:
 Shared cannot be implicitly cast to unshared. Just like const cannot be 
 implicitly cast to mutable.
But you can implicitly cast unshared to shared, right?
No. There is no implicit casting or else you can have data that is shared and unshared at the same time. It will be up to the coder to ensure only one is happening at a time.
Yeah, I saw your (was it you?) example of how that would become problematic. Did you see my "scope locks" idea as a possible way to safely move data between the shared & unshared realms?
Aug 07 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Russell Lewis" wrote
 Steven Schveighoffer wrote:
 "Russell Lewis" wrote
 Walter Bright wrote:
 Shared cannot be implicitly cast to unshared. Just like const cannot be 
 implicitly cast to mutable.
But you can implicitly cast unshared to shared, right?
No. There is no implicit casting or else you can have data that is shared and unshared at the same time. It will be up to the coder to ensure only one is happening at a time.
Yeah, I saw your (was it you?) example of how that would become problematic. Did you see my "scope locks" idea as a possible way to safely move data between the shared & unshared realms?
I think there may be no middle ground, as in order for locks to work, every access to a locked variable must be through the lock. If you have 2 references to a variable, one that is shared and one that is not, locking on the shared variable does nothing to prevent the unshared variable from being accessed without the lock. I think the middle ground simply needs to do the most safe thing (i.e. treat as shared), but not allow implicit casting to unshared or shared. However, in this case, you incur a possible performance hit when it might not be necessary. It might be that the middle ground is simply undesirable, so you have to do explicit casting. I'm not sure. -Steve
Aug 08 2008
parent Russell Lewis <webmaster villagersonline.com> writes:
Steven Schveighoffer wrote:
 I think there may be no middle ground, as in order for locks to work, every 
 access to a locked variable must be through the lock.  If you have 2 
 references to a variable, one that is shared and one that is not, locking on 
 the shared variable does nothing to prevent the unshared variable from being 
 accessed without the lock.
 
 I think the middle ground simply needs to do the most safe thing (i.e. treat 
 as shared), but not allow implicit casting to unshared or shared.
 
 However, in this case, you incur a possible performance hit when it might 
 not be necessary.  It might be that the middle ground is simply undesirable, 
 so you have to do explicit casting.
I think that you misunderstood my locking idea. My idea was that there was only one root reference to a variable, and you have to grab the lock to get to it. So you can treat it as unshared while you hold the lock (with all the performance benefits, and code conveniences like ++, that you get with unshared data) but while you do not hold the lock it is absolutely inaccessible. Put more explicitly, a "locked" variable has three modes: shared, in accessible to all locked in read mode, unshared const scope to one thread locked in write mode, unshared scope to one thread Of course, you can't have external pointers pointing into the data structure (from outside the lock), but inside the lock it's perfectly OK to have pointers to other things inside the lock (or to external shared data). So you could, for instance, build a doubly-linked list; you just make the sure that your global variable, which points to the head of the list, is declared as "locked".
Aug 08 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Thu, 31 Jul 2008 04:52:16 +0400, Walter Bright  
<newshound1 digitalmars.com> wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
Hello, volatile! :)
Jul 31 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant. Allowing access to thread-local globals is a bad idea.
Jul 31 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Walter Bright Wrote:
 
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
 Allowing access to thread-local globals is a bad idea.
Why? Global thread local storage is even enshrined into C++0x.
Jul 31 2008
parent reply superdan <super dan.org> writes:
Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:
 
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
looks 2 me more like more of the confusion in yesterthread.
 Allowing access to thread-local globals is a bad idea.
Why? Global thread local storage is even enshrined into C++0x.
99% of the global shit i ever defined i wanted to be thread local. i had to take special measures to make it so. dealing with globals in one thread is shitty to boot. using globals to communicate across threads is sheer suicide.
Jul 31 2008
parent reply downs <default_357-line yahoo.de> writes:
superdan wrote:
 Walter Bright Wrote:
 
 Jason House wrote:
 Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
looks 2 me more like more of the confusion in yesterthread.
 Allowing access to thread-local globals is a bad idea.
Why? Global thread local storage is even enshrined into C++0x.
99% of the global shit i ever defined i wanted to be thread local. i had to take special measures to make it so. dealing with globals in one thread is shitty to boot. using globals to communicate across threads is sheer suicide.
What about cases that depend on external resources, like a global buffer object for HTTP downloads? In that case you want cached results to be available to as many threads as possible, especially if the respective server has a high latency. --downs
Aug 01 2008
parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from downs (default_357-line yahoo.de)'s article
 superdan wrote:
 Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
looks 2 me more like more of the confusion in yesterthread.
 Allowing access to thread-local globals is a bad idea.
Why? Global thread local storage is even enshrined into C++0x.
99% of the global shit i ever defined i wanted to be thread local. i had to
take special measures to make it so.
 dealing with globals in one thread is shitty to boot. using globals to
communicate across threads is sheer suicide.
 What about cases that depend on external resources, like a global buffer object
for HTTP downloads?
 In that case you want cached results to be available to as many threads as
possible, especially if the respective server has a high latency. Yup. This is pretty much the only time I use globals in my apps-- if there's some huge data structure I want to reference in all my threads. A user list... something like that. In a language like Erlang, that user list would probably be managed by a distinct process and would serve requests from other processes that wanted to perform operations on it. Without shared data in D I'd do pretty much the same thing. All D would need is a solid messaging system. libd has one built-in, but we avoided this with Tango because it would effectively change the language. Sean
Aug 01 2008
prev sibling next sibling parent reply Jesse Phillips <jessekphillips gmail.com> writes:
On Wed, 30 Jul 2008 17:52:16 -0700, Walter Bright wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
I haven't done much threading, so this sounds mostly good. On question I have relates to when a single threaded program/component is using libraries designed to support multithreading (thus it asks for a shared value). You aren't really doing any sharing you just wanted to call the function for what it does. Would this never happen? Do I now have to cast my unshared to shared even though I'm not interested in sharing? My main point, is that if I'm writing a single threaded program, I shouldn't care about sharing even if the library I'm using does.
Jul 31 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jesse Phillips wrote:
 Would this never happen? Do I now have to cast my unshared to shared even 
 though I'm not interested in sharing? My main point, is that if I'm 
 writing a single threaded program, I shouldn't care about sharing even if 
 the library I'm using does.
Unshared can be implicitly cast to shared, so you shouldn't have to.
Jul 31 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:
 
 Unshared can be implicitly cast to shared, so you shouldn't have to.
That should not be implicit. For one, thread-local garbage collection of non-shared data would leave dangling references to garbage memory. Two, the guarantees for shared data are lost. Code using the non-shared reference will not respect that the variable really is shared.
Aug 01 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Walter Bright Wrote:
 
 Unshared can be implicitly cast to shared, so you shouldn't have
 to.
That should not be implicit. For one, thread-local garbage collection of non-shared data would leave dangling references to garbage memory.
True, but the memory allocation system shouldn't be (and isn't) built that way.
 Two, the guarantees for shared data are lost. Code using the
 non-shared reference will not respect that the variable really is
 shared.
That would be true if shared were implicitly cast to unshared, but that's not the case. It's unshared implicitly cast to shared.
Aug 01 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:
 
 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
Let's say I have an object that was originally written assuming non-shared access and contains one member function with no arguments. Some later coder comes by and decides it'd be nice to share this object among threads and creates a shared instance of it. There's no way to know if calling the member function is safe. Maybe it accesses a non-shared global variable. Maybe a call to an encapsulated object's member function uses a non-shared global variable. The maintainer must be extremely careful and scour the code to ensure there's no accidental sharing that was not intended. Maybe I'm reading too much into stuff again, but the article did say "The proposal is to make accidental sharing impossible".
Aug 01 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Jason House" wrote
 Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
Let's say I have an object that was originally written assuming non-shared access and contains one member function with no arguments. Some later coder comes by and decides it'd be nice to share this object among threads and creates a shared instance of it. There's no way to know if calling the member function is safe. Maybe it accesses a non-shared global variable. Maybe a call to an encapsulated object's member function uses a non-shared global variable. The maintainer must be extremely careful and scour the code to ensure there's no accidental sharing that was not intended. Maybe I'm reading too much into stuff again, but the article did say "The proposal is to make accidental sharing impossible".
I have a feeling that the shared/unshared comes with a requriement for 'shared' functions. That is, in order to call a function on an object that is 'shared', you have to call a function where the 'this' pointer is shared: class C { shared f(); // can call on a shared C instance, means the 'this' pointer is shared f(); // can call on an unshared C instance } -Steve
Aug 01 2008
next sibling parent Jason House <jason.james.house gmail.com> writes:
Steven Schveighoffer Wrote:

 "Jason House" wrote
 Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
This is one of my 3 big wishes for the D language. The artical talks about shared being transitive just like const/invariant. I certainly hope it's more like pure than transitive invariant.
Pure doesn't apply to data types, it applies to functions. I don't know what you mean.
Let's say I have an object that was originally written assuming non-shared access and contains one member function with no arguments. Some later coder comes by and decides it'd be nice to share this object among threads and creates a shared instance of it. There's no way to know if calling the member function is safe. Maybe it accesses a non-shared global variable. Maybe a call to an encapsulated object's member function uses a non-shared global variable. The maintainer must be extremely careful and scour the code to ensure there's no accidental sharing that was not intended. Maybe I'm reading too much into stuff again, but the article did say "The proposal is to make accidental sharing impossible".
I have a feeling that the shared/unshared comes with a requriement for 'shared' functions. That is, in order to call a function on an object that is 'shared', you have to call a function where the 'this' pointer is shared: class C { shared f(); // can call on a shared C instance, means the 'this' pointer is shared f(); // can call on an unshared C instance } -Steve
I'd much prefer to discuss the problematic use case and either confirming or rejecting that D will help protect against it. Your definition implies that such programming errors will not be caught. This seems against the spirit of the article.
Aug 01 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 I have a feeling that the shared/unshared comes with a requriement for 
 'shared' functions.  That is, in order to call a function on an object that 
 is 'shared', you have to call a function where the 'this' pointer is shared:
That's right. Shared objects can only call shared or synchronized methods.
Aug 01 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 Jason House wrote:
 Walter Bright Wrote:
 
 Unshared can be implicitly cast to shared, so you shouldn't have
 to.
That should not be implicit. For one, thread-local garbage collection of non-shared data would leave dangling references to garbage memory.
True, but the memory allocation system shouldn't be (and isn't) built that way.
I don't see how memory allocation fits into it. It's about deallocation and garbage collection. I believe the single-threaded garbage collection would only scan memory for the thread in question and would miss shared data's reference to non-shared data.
 
 
 Two, the guarantees for shared data are lost. Code using the
 non-shared reference will not respect that the variable really is
 shared.
That would be true if shared were implicitly cast to unshared, but that's not the case. It's unshared implicitly cast to shared.
I don't see how having one thread with a reference to unshared data and N threads with shared references to the unshared data can work. Maybe the shared references will play nice with each other, but they will mess up assumptions by the unshared code. What am I missing?
Aug 01 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Jason House (jason.james.house gmail.com)'s article
 Walter Bright Wrote:
 Jason House wrote:
 Walter Bright Wrote:

 Unshared can be implicitly cast to shared, so you shouldn't have
 to.
That should not be implicit. For one, thread-local garbage collection of non-shared data would leave dangling references to garbage memory.
True, but the memory allocation system shouldn't be (and isn't) built that way.
I don't see how memory allocation fits into it. It's about deallocation and garbage collection. I believe
the single-threaded garbage collection would only scan memory for the thread in question and would miss shared data's reference to non-shared data. I think the only way this can work is if you make 'shared' a bit like 'pure' in that a shared object can't reference non-shared data. Then you have a full-on "stop the world" GC for the shared data area. With this approach you'd at least know that most of your GC cycles would be thread-local, which is better than none of them. If the user wants to bypass this they can always cast unshared to shared when assigning a shared reference to it. This gets back to what I said about shared being transitive. The sticky part would be enforcing it--I guess you'd have to do so at the point of assignment: class C { int* x; shared void put( int* y ) { x = y; // error, y is not "shared(int*)" } } It really is a lot like const, isn't it? Sean
Aug 01 2008
parent reply JAnderson <ask me.com> writes:
Sean Kelly wrote:
 == Quote from Jason House (jason.james.house gmail.com)'s article
 Walter Bright Wrote:
 Jason House wrote:
 Walter Bright Wrote:

 Unshared can be implicitly cast to shared, so you shouldn't have
 to.
That should not be implicit. For one, thread-local garbage collection of non-shared data would leave dangling references to garbage memory.
True, but the memory allocation system shouldn't be (and isn't) built that way.
I don't see how memory allocation fits into it. It's about deallocation and garbage collection. I believe
the single-threaded garbage collection would only scan memory for the thread in question and would miss shared data's reference to non-shared data. I think the only way this can work is if you make 'shared' a bit like 'pure' in that a shared object can't reference non-shared data. Then you have a full-on "stop the world" GC for the shared data area. With this approach you'd at least know that most of your GC cycles would be thread-local, which is better than none of them. If the user wants to bypass this they can always cast unshared to shared when assigning a shared reference to it. This gets back to what I said about shared being transitive. The sticky part would be enforcing it--I guess you'd have to do so at the point of assignment: class C { int* x; shared void put( int* y ) { x = y; // error, y is not "shared(int*)" } } It really is a lot like const, isn't it? Sean
My thought was you could use Ref counting for shared memory and mark and sweep for unshared. -Joel
Aug 02 2008
parent reply Jason House <jason.james.house gmail.com> writes:
JAnderson Wrote:
 
 My thought was you could use Ref counting for shared memory and mark and 
   sweep for unshared.
That's a really good idea. Mark and sweep (as currently implemented in D) can be very expensive with multiple threads.
Aug 02 2008
parent JAnderson <ask me.com> writes:
Jason House wrote:
 JAnderson Wrote:
  
 My thought was you could use Ref counting for shared memory and mark and 
   sweep for unshared.
That's a really good idea. Mark and sweep (as currently implemented in D) can be very expensive with multiple threads.
Thanks, A couple more thoughts. With a naive approach a lock would have to be acquired every time something was referenced counted in the unshared. There are 2 ways I can think of to counter this: 1) Have a thread local ref count. Then the shared memory would simply have a ref count of the number threads that have access to that piece of memory. When the memory is first required it would acquire a lock and increment the count in the shared as well as the local. From then on it would only increment/decrement its local ref count until it reached 0 then it would have to update the shared one again. 2) The local thread doesn't contain a ref count but instead has a proxy memory for each shared memory reference. When it goes to delete the proxy it tells the shared memory to dec its count. 3) Perhaps ref counting isn't need after all. All that is really needed is a table in the shared memory that simply details what threads have what pieces of memory. When the shared GC runs it will also go over that list and see that some pieces of memory are still being held on to. Local threads would only need to lock/unlock that portion of memory. The shared GC would no be ableble to run while this memory is being accessed. The advantage here is that each thread has its own bit of memory in the shared to work with. Of course race conditions will still be a problem to solve. -Joel
Aug 02 2008
prev sibling next sibling parent reply Walter Bright <walter nospamm-digitalmars.com> writes:
Steven Schveighoffer Wrote:
 I'm thinking more in the case of functions.  If I have a function foo, and I 
 want to pass my shared data version to it, I need to re-implement foo with 
 the parameters as being shared.  Imagine a function with several parameters, 
 in which you want to pass a combination of shared/unshared.  That's 2^n 
 variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.
 I think at the very least, for this to be palatable, there needs to be 
 another modifier that unifies shared and unshared.  Similar to how const 
 unifies mutable and invariant.
Shared unifies shared and unshared.
Aug 01 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright" wrote
 Steven Schveighoffer Wrote:
 I'm thinking more in the case of functions.  If I have a function foo, 
 and I
 want to pass my shared data version to it, I need to re-implement foo 
 with
 the parameters as being shared.  Imagine a function with several 
 parameters,
 in which you want to pass a combination of shared/unshared.  That's 2^n
 variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.
I'm assuming you read my previous example, but I'll rewrite it to demonstrate what I'm trying to show: class sharedObj { private int *_x; synchronized shared int x() {return *_x;} synchronized shared int x(int y) {*_x = y;} synchronized shared void rebind(shared int *y) {_x = y;} } shared sharedObj obj; static this() { obj = new sharedObj; } int *x2; void bar() { obj.x = x2; *x2 = 3; // is this supposed to be guaranteed safe? } Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean. I was under the impression that 'unshared' means 'lock free', which cannot be enforcable if you can implicitly cast away the 'lock free' aspect of it. ??? -Steve
Aug 01 2008
next sibling parent Jason House <jason.james.house gmail.com> writes:
Steven Schveighoffer Wrote:

 "Walter Bright" wrote
 Steven Schveighoffer Wrote:
 I'm thinking more in the case of functions.  If I have a function foo, 
 and I
 want to pass my shared data version to it, I need to re-implement foo 
 with
 the parameters as being shared.  Imagine a function with several 
 parameters,
 in which you want to pass a combination of shared/unshared.  That's 2^n
 variations you have to write.
Not necessary, just make them shared. Unshared implicitly converts to shared, so that works. Putting a fence around an unshared read doesn't break anything, etc.
I'm assuming you read my previous example, but I'll rewrite it to demonstrate what I'm trying to show: class sharedObj { private int *_x; synchronized shared int x() {return *_x;} synchronized shared int x(int y) {*_x = y;} synchronized shared void rebind(shared int *y) {_x = y;} } shared sharedObj obj; static this() { obj = new sharedObj; } int *x2; void bar() { obj.x = x2; *x2 = 3; // is this supposed to be guaranteed safe? } Now, Let's say you have thread 1 which calls bar. So now thread 1's x2 and obj._x point to the exact same data, which is both viewed as shared and unshared at the same time. Is this something that should be allowed? Would you not make the assumption that you can do whatever you want with what x2 points to without synchronization because it is unshared? Maybe I don't completely understand what you are intending for shared to mean. I was under the impression that 'unshared' means 'lock free', which cannot be enforcable if you can implicitly cast away the 'lock free' aspect of it. ??? -Steve
Uh oh Steve, you're starting to sound like me! I made the 2^n comment in the context of the const system a while back and now you're looking at how globals might break a transitve data type system... I could have sworn you were the loudest voice against my ideas!
Aug 01 2008
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Steven Schveighoffer wrote:
 Now, Let's say you have thread 1 which calls bar.  So now thread 1's x2 and 
 obj._x point to the exact same data, which is both viewed as shared and 
 unshared at the same time.  Is this something that should be allowed?  Would 
 you not make the assumption that you can do whatever you want with what x2 
 points to without synchronization because it is unshared?  Maybe I don't 
 completely understand what you are intending for shared to mean.
Eh, I think you've got me there. Looks like unshared cannot be implicitly converted to shared.
Aug 01 2008
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Walter Bright wrote:
 Steven Schveighoffer wrote:
 Now, Let's say you have thread 1 which calls bar.  So now thread 1's 
 x2 and obj._x point to the exact same data, which is both viewed as 
 shared and unshared at the same time.  Is this something that should 
 be allowed?  Would you not make the assumption that you can do 
 whatever you want with what x2 points to without synchronization 
 because it is unshared?  Maybe I don't completely understand what you 
 are intending for shared to mean.
Eh, I think you've got me there. Looks like unshared cannot be implicitly converted to shared.
Akin to why const cannot be implicitly converted to invariant, no? -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 11 2008
parent reply dsimcha <dsimcha yahoo.com> writes:
One thing that recently popped into my mind about the shared/unshared
discussion:
 What about arrays, etc that are manipulated by multiple threads, but in such a
way that each thread is guaranteed not to touch the same elements as any other
thread, and to never reallocate the array?  This is something I actually do, for
such things as filling in large matrices.  If I understand this proposal
correctly, if the array is unshared, multiple threads can't touch it.  If it is
shared, the compiler will automatically make it synchronized.  In this case, the
synchronization overhead might be large and unnecessary.  If I have each thread
write to separate, unshared data structures and merge them together later, then
I'm adding needless complexity to my code.
Aug 11 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
  What about arrays, etc that are manipulated by multiple threads, but in such a
 way that each thread is guaranteed not to touch the same elements as any other
 thread, and to never reallocate the array?
If you take a slice of an array [a..b] you don't copy data, so if threads can work on adjacent parts you can slice it in parts that are unshared, and then use the whole usliced block of data... Bye, bearophile
Aug 11 2008
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
== Quote from dsimcha (dsimcha yahoo.com)'s article
 One thing that recently popped into my mind about the shared/unshared
discussion:
  What about arrays, etc that are manipulated by multiple threads, but in such a
 way that each thread is guaranteed not to touch the same elements as any other
 thread, and to never reallocate the array?  This is something I actually do,
for
 such things as filling in large matrices.  If I understand this proposal
 correctly, if the array is unshared, multiple threads can't touch it.  If it is
 shared, the compiler will automatically make it synchronized.  In this case,
the
 synchronization overhead might be large and unnecessary.  If I have each thread
 write to separate, unshared data structures and merge them together later, then
 I'm adding needless complexity to my code.
For arrays with elements smaller than the bus width or for unaligned arrays there are still word tearing issues, which makes such an approach risky at best. Less importantly, depending on the size and alignment of the array the threads could end up all competing for the same cache line, which would render parallelization of the algorithm largely pointless unless the computation is extremely expensive. It's almost always better to have each thread work on a copy of the data and then merge it later. Sean
Aug 11 2008
prev sibling parent mort <mortm gmail.com> writes:
Walter Bright Wrote:
 Shared unifies shared and unshared.
It seems that you want the semantics for shared to be ``allocated on either the shared heap or the local heap'' and for non-shared to be ``allocated on a thread local heap''. Is that right? If so, then it seems the only safe cast is from non-shared to *const* shared. I think that was what Steven's example was meant to demonstrate (though I had trouble following it).
Aug 01 2008
prev sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:

 http://www.reddit.com/comments/6u7k0/sharing_in_d/
When can we expect to see this in D2? For the first time since moving to Tango, I'm considering moving back to Phobos. A monolithic garbage collector kills scalability for my data intensive application. Of couse all interesting hardware is 64 bit, so I may need to be more patient...
Aug 04 2008
parent Walter Bright <walter nospamm-digitalmars.com> writes:
Jason House Wrote:
 When can we expect to see this in D2? For the first time since moving to
Tango, I'm considering moving back to Phobos.
It'll come in stages. For example, D 2.0 already supports thread local storage for globals. Next will probably come the 'sharing' type constructor, and name mangling. All this will phase in over the next 3 months or so.l
Aug 04 2008