D
Don Y
Hi Tim,
Yes, hence my comments. To take (roughly) the cases presented
in the paper:
4.1) You *know* when writing multithreaded code that
control to *any* shared object has to be arbitrated
(this is, IMO, one of the key points the article
tries to skirt... as if wanting NOT to have the
developer be concerned with these issues -- an
admirable goal but not one that rules out threading
libraries as a possible solution). The examples given
in this section show *no* explicit acknowledgement that
the objects/data are shared nor any mechanism to ensure
that sharing works (i.e., not even a library call is
present!)
4.2) is yet another example of the above. Except, in
addition to the lack of any formal access control
mechanism, there is now the acknowledgement that a
datum may span "objects". I.e., yet another case of
wanting to protect the programmer from things he might
have failed to notice (though still not anything that
precludes a library based solution)
4.3) Frankly, I don't see the problem here (too early
in the day?). Aside from the INEFFICIENCY that is
introduced... where is the code "broken"? OK, the
compiler's optimizations may have been unfortunate
but does the code perform as intended?
5.1) Makes the efficiency argument explicit -- and
goes to my comment regarding truly parallel implementations.
for (my_prime = start; my_prime < 10000; ++my_prime) {
if (!get(my_prime)) {
for (mult = my_prime; mult < 100000000; mult += my_prime) {
if (!get(mult)) {
set(mult);
}
}
}
}
is written *assuming* multiple threads can access the array
(sieve) hidden behind get()/set() inexpensively and concurrently.
The author then complains that the implementation of set()/get()
can cause problems -- for exactly the same reasons in 4.x.
I.e., the authors are advocating freeing the developer from
any concerns associated with implementing concurrency.
"Let's let the compiler consider all of these possible
cases and craft some rules that are *different* from the
rules a multithreaded programmer already SHOULD know..."
Yet, complain when safeguarding against those problems
(e.g., by invoking a mutex per shared object) becomes
"expensive": "Where's *my* free lunch??"
Sure, it would be delightful to *have* such protection
(i.e., scissors that automatically cover their blades
when they detect that you are "running with them").
But, I don't see how that PREVENTS a library based solution
from working.
E.g., wrap the internals of get()/set() with a lock.
The concurrency problems go away -- but performance
plummets. BECAUSE YOUR THREADS ARE COMPETING FOR TOO
MUCH DATA.
OTOH, having a thread doing this while another thread is
balancing your checkbook and still another is darning
your socks incurs NO performance penalty.
Yeah, its unfortunate that I can't get 500 digits of
precision in all of my math "for free". But, I don't
*expect* it to be free!
I don't see that. I think that's only the case if you want
the compiler to be able to implement the safeguards *for* you.
And, I only see it pertaining to certain types of optimizations
(if the compiler doesn't make those optimizations, then your
code isn't at risk for them!)
I.e., I don't see how that PRECLUDES the use of a library.
Compilers are unaware of interrupts. An interrupt can occur
between any two instructions. Does that mean a you can't write
code in C that will operate in the presence of interrupts?
What it *does* mean is that anything that your code could be
doing that an interrupt might want to ASYNCHRONOUSLY interfere
with needs to be protected against that interference. Likewise,
anything your code wants to be able to *convey* to your ISR
needs to take precautions that the ISR sees "the whole picture"
and not just *part* of it.
Am I missing something, here?
Did you read the paper?
Yes, hence my comments. To take (roughly) the cases presented
in the paper:
4.1) You *know* when writing multithreaded code that
control to *any* shared object has to be arbitrated
(this is, IMO, one of the key points the article
tries to skirt... as if wanting NOT to have the
developer be concerned with these issues -- an
admirable goal but not one that rules out threading
libraries as a possible solution). The examples given
in this section show *no* explicit acknowledgement that
the objects/data are shared nor any mechanism to ensure
that sharing works (i.e., not even a library call is
present!)
4.2) is yet another example of the above. Except, in
addition to the lack of any formal access control
mechanism, there is now the acknowledgement that a
datum may span "objects". I.e., yet another case of
wanting to protect the programmer from things he might
have failed to notice (though still not anything that
precludes a library based solution)
4.3) Frankly, I don't see the problem here (too early
in the day?). Aside from the INEFFICIENCY that is
introduced... where is the code "broken"? OK, the
compiler's optimizations may have been unfortunate
but does the code perform as intended?
5.1) Makes the efficiency argument explicit -- and
goes to my comment regarding truly parallel implementations.
for (my_prime = start; my_prime < 10000; ++my_prime) {
if (!get(my_prime)) {
for (mult = my_prime; mult < 100000000; mult += my_prime) {
if (!get(mult)) {
set(mult);
}
}
}
}
is written *assuming* multiple threads can access the array
(sieve) hidden behind get()/set() inexpensively and concurrently.
The author then complains that the implementation of set()/get()
can cause problems -- for exactly the same reasons in 4.x.
I.e., the authors are advocating freeing the developer from
any concerns associated with implementing concurrency.
"Let's let the compiler consider all of these possible
cases and craft some rules that are *different* from the
rules a multithreaded programmer already SHOULD know..."
Yet, complain when safeguarding against those problems
(e.g., by invoking a mutex per shared object) becomes
"expensive": "Where's *my* free lunch??"
Sure, it would be delightful to *have* such protection
(i.e., scissors that automatically cover their blades
when they detect that you are "running with them").
But, I don't see how that PREVENTS a library based solution
from working.
E.g., wrap the internals of get()/set() with a lock.
The concurrency problems go away -- but performance
plummets. BECAUSE YOUR THREADS ARE COMPETING FOR TOO
MUCH DATA.
OTOH, having a thread doing this while another thread is
balancing your checkbook and still another is darning
your socks incurs NO performance penalty.
Yeah, its unfortunate that I can't get 500 digits of
precision in all of my math "for free". But, I don't
*expect* it to be free!
boil down to
removing the need for the developer to "take precautions"
(i.e., manually ensure that the compiler doesn't "get ahead
of him") along with wanting to be able to use the language
to *efficiently* implement truly parallel threads of
execution. [snip elaboration]
The problem is the compiler is operating at the wrong level of
abstraction. Whether the compiler "gets ahead" of a developer
(a frightening concept in and of itself, but let's ignore
that) doesn't matter, because the operating environment that
(non-thread-aware) compilers generate code for doesn't make
strong enough guarantees about inter-thread or inter-processor
memory consistency. To get threads to work usably, at least
part of the compiler needs to be aware of a lower level of
abstraction, below the architectural level for a single
process (which is where essentially all pre-thread-aware
compilers operate).
I don't see that. I think that's only the case if you want
the compiler to be able to implement the safeguards *for* you.
And, I only see it pertaining to certain types of optimizations
(if the compiler doesn't make those optimizations, then your
code isn't at risk for them!)
I.e., I don't see how that PRECLUDES the use of a library.
Compilers are unaware of interrupts. An interrupt can occur
between any two instructions. Does that mean a you can't write
code in C that will operate in the presence of interrupts?
What it *does* mean is that anything that your code could be
doing that an interrupt might want to ASYNCHRONOUSLY interfere
with needs to be protected against that interference. Likewise,
anything your code wants to be able to *convey* to your ISR
needs to take precautions that the ISR sees "the whole picture"
and not just *part* of it.
Am I missing something, here?