On 07/11/18 16:56, Tom Gardner wrote:
> On 07/11/18 08:51, David Brown wrote:
>> On 06/11/18 17:11, Tom Gardner wrote:
>>> On 06/11/18 15:05, David Brown wrote:
>>>> On 06/11/18 15:38, Tom Gardner wrote:
>>>>> On 06/11/18 14:01, Phil Hobbs wrote:
>>>>>> On 11/6/18 7:36 AM, Tom Gardner wrote:
>>>>>>> On 06/11/18 11:28, David Brown wrote:
>>>>>>>> On 05/11/18 19:44, Clive Arthur wrote:
>>>>>>>>> On 05/11/2018 18:01, Tom Gardner wrote:
>>>>
>>>> <snipped>
>>>>
>>>>>>>
>>>>>>> That complexity is a serious issue. If given a piece
>>>>>>> of code, most developers won't understand which
>>>>>>> combination of compiler flag must/mustn't be used.
>>>>>>
>>>>>> Code that works on some compiler settings and not others gives me the
>>>>>> heebie-jeebies. People often talk about "optimizer bugs" that really
>>>>>> aren't anything of the sort. Of course vaguely-defined language
>>>>>> features such as 'volatile' and old-timey thread support don't help.
>>>>>> (Things have been getting better on that front, I think.)
>>>>>
>>>>> Me too, but it is unclear to me that Things
>>>>> Are Getting Better. If they are it is /very/
>>>>> slow and will in many cases be constrained by
>>>>> having to use old variants of a language.
>>>>>
>>>>
>>>> One thing that I can think of that is "getting better" is threading in
>>>> C11 and C++11. I don't see it being particularly popular in C11 -
>>>> people use other methods, and embedded developers are often still using
>>>> older C standards. C++11 gives more useful threading features, which
>>>> have been extended in later versions - they give more reasons to use
>>>> the
>>>> language's threading functionality rather than external libraries.
>>>>
>>>> The other new feature (again, from C++11 and C11) is atomic support.
>>>>
>>>> These are nice, but I think that most people who understands and uses
>>>> "atomic" probably already understood how to use "volatile" correctly.
>>>
>>> Yes, but /very/ slowly.
>>>
>>
>> Agreed. I think especially in C, the multi-threading and atomic stuff
>> was too little, too late. Anyone wanting this is already using it via
>> libraries.
>
> I'm from the time when C explicitly regarded that as a
> library issue not a language issue - and explicitly avoided
> giving libraries the necessary primitives.
>
> At least things have moved on (a bit) since then!
>
In small systems embedded programming, most RTOS's are written in C90,
with a bit of implementation-specific (compiler and target) parts. No,
things have not moved on - not nearly fast enough for my liking, at
least in some areas. A lot of software like this is written to be
portable, and to support the lowest common denominator - and that means
ancient C90 compilers on brain-dead 8-bit architectures.
Embedded development - both hardware and software - is often a curious
mixture of wanting the latest and greatest, fastest, smallest and
cheapest, while simultaneously wanting tried and tested technology that
has proven its worth over a decade or two.
>
>
>> In C++, the case is a bit different as the standard C++11 threading
>> things give you many advantages over OS calls and macros. It is much
>> nicer to simply create a local lock object and then know that you hold
>> the lock for as long as that object is in scope, than to have to have a
>> call to get the lock, then have matching releases on all possible exit
>> points from the function (including exceptions). At least some of this
>> could have come earlier, of course, but language improvements in C++11
>> with "auto" and better templates gave an overall better system.
>
> Agreed. An OS call to do a context switch might be OK
> on a PDP11 "workstation", but beyond that it has always
> sucked.
>
Do you mean cooperative multi-tasking as distinct from pre-emptive
multi-tasking? Each method has its advantages and disadvantages.
The multi-tasking and context switches are always going to boil down to
OS calls in the end, but the interface can make a big difference. In
C11, using a mutex to protect some data might be like this (ignoring
errors) :
mtx_t lock;
uint64_t counter;
void init(void) {
mtx_init(&lock, mtx_plain);
}
void finit(void) {
mtx_destroy(&lock);
}
void increment(void) {
mtx_lock(&lock);
counter++;
mtx_unlock(&lock);
}
You need manual creation and destruction of the mutex, manual lock and
unlock. Good luck keeping track if you need to pass a locked mutex onto
other functions.
C code using OS interfaces directly, rather than C11, will be very similar.
In C++, you have:
std::mutex lock;
uint64_t counter;
void increment(void) {
std::lock_guard<std::mutex> guard(lock);
counter++;
}
As long as the lock_guard is in scope, the lock is locked. These kind
of things make it easier to get code right, and harder to get it wrong.
>
>
>>> The core multiprocessing concepts were known in the mid 70s,
>>> but quite reasonably they didn't make it into K&R C.
>>>
>>> They first made their way into systems in the early/mid 80s,
>>> in Cedar/Mesa and Occam. They were, unfortunately, completely
>>> ignored in C++, because it was addressing (and creating)
>>> different problems.
>>>
>>
>> (I don't know Cedar/Mesa, but Occam was for handling completely
>> different kinds of problems. It was for massively parallel systems,
>> often SIMD, rather than multiple independent threads.)
>
> I don't know Cedar/Mesa either, but Occam heartily embraced
> parallelism whereas C/C++ was always (at best) ambivalent
> about it.
>
> Yes, Occam had/has its limitations, but it showed what was
> possible. Perhaps with the demise of "clock-rate inflation"
> people will pay more attention to parallel behaviour and
> semantics. Some languages are already going down that path.
>
>
>> C and C++ lived in a serial world, and you used OS features to work with
>> multiple threads or synchronisation.
>
> Agreed. Having used hardware and C for my embedded real-time
> applications, that attitude always frustrated me.
>
>
>
>> Part of this was, I think, a chicken-and-egg effect of C being tightly
>> bound with *nix, and the *nix world being slow to use threads. In *nix,
>> processes are cheap and inter-process communication is easy and
>> efficient. There was little incentive to have threads and more
>> efficient (but harder) communication and synchronisation between
>> threads. Windows needed threads because processes were, and still are,
>> hugely expensive in comparison.
>>
>> Without threads in the OS, there is no need for threading support in a
>> language. Without threading support (and a memory model, atomics, and
>> synchronisation instructions), it is hard to use threads in code and
>> therefore no point in having them in the OS.
>
> Agreed. A chicken and egg situation.
>
> What has irritated me is some people's belief that
> parallelism at the OS process level is necessary,
> sufficient, and the most beneficial solution.
>
I don't know quite what you mean here. Some languages have support for
parallelism, but it is done in coordination with the OS. The underlying
mechanism might be processes, threads, or fibres, or even different
computer nodes, but the OS needs to be in control of where things run.
Languages with parallel support just make it all simpler to use. So
when you use C++17 and say that a search through a large container is to
use the "parallel execution policy", it is the OS that handles the
threads and the C++17 library that splits the search across the threads.
But if you mean processes vs. threads, then for many tasks it is easier
to keep the interaction between the parts clean and clear, lowering the
risks of deadlocks and other problems, with processes than threads.
This is primarily because the more efficient, but riskier,
synchronisation and sharing methods available in threads are not
possible or not as simple with processes.
>
>>> They were used in mainstream languages/environments in the
>>> mid 90s, i.e. almost a quarter of a century ago.
>>>
>>> Some of the higher-level concepts continue to be included
>>> in newer languages.
>>>
>>> So by a very generous definition, C/C++ is catching up with
>>> techniques that were known to be good 30 years ago, and
>>> that have been in widespread use for 20 years.
>>> Not impressive.
>>>
>>> The main reason C/C++ continues to be used is history:
>>> there's a lot of code out there, and people are familiar
>>> with (old versions of) it. Ditto COBOL.
>>
>> The main reason C and C++ continue to be used is that they are the best
>> choice available for many tasks.
>
> Yes, but that's like saying Ford Transits are used because
> they are the best choice available for tasks. And then
> extending that to bicycle-delivery tasks, off-road tasks,
> and racing tasks.
>
No, that is not a fair comparison. There are rarely any uses for which
a Ford Transit is significantly better than any other similarly sized van.
The appropriate comparison is that the /vans/ are used because they are
often the best choice available for certain tasks - even if bicycles are
better for other purposes.
>
>> (Note that there is no "C/C++"
>> language - they are different, they have diverged more and more in both
>> style and usage. There is plenty of cooperation between them, and the
>> tools used are often the same, but they are different types of language.)
>
> Agreed. I use the notation for simplicity where the
> two have common characteristics.
>
> I continue to be surprised at the number of people that
> still think C is a subset of C++.
>
C is close to a subset of C++, but not entirely. A good deal of C code
does not use the features of C that are not in C++ - at most, small
modifications would be needed to make it equally valid C++.
>
>
>> For low-level work - for small embedded systems, for key parts of OS's,
>> for libraries that need maximal efficiency, and as a "lingua francais"
>> of software, nothing comes close to C. Part of this comes precisely
>> because of its stability and resistance to change.
>
> Now that's a far more contentious statement.
>
Which part do you contend? I covered quite a few things in that paragraph.
>
>> For mid-level work, C++ is still a top choice. And it continues to
>> evolve and gain new features - modern C++ is not the same language as it
>> was a decade ago.
>
> Apparently even Scott Meyers has given up trying to
> keep abreast of the C++ changes!
>
It has grown to a big system, and a big library. The same applies to
lots of things. Do you think anyone knows all the Java libraries, or
Python libraries? Do you think anyone knows the all the details of the
Python language, never mind the libraries?
>
>
>> This does not mean that C or C++ are the best choices for all the tasks
>> for which they are used. It also does not mean we could not have better
>> languages. But they are good enough for a great many uses, and combined
>> with the history - the existing code, the existing developers, the
>> existing tools - you have to have a /much/ better language in order to
>> replace them.
>
> Agreed.
>
> There are languages that are much better in significant domains.
>
> One of the key insights I had a couple of decades ago was
> that the papers on C/C++ always referred to other C/C++ papers.
> In contrast the papers on other languages referred to many other
> languages[1]. The net result was that the C/C++ community was smugly
> self-satisfied and that there was nothing they could learn from
> wider theory and practical experience.
>
> [1] an excellent example is Gosling's Java whitepaper.
> http://www.stroustrup.com/1995_Java_whitepaper.pdf
> (Yes, that domain tends to weaken my point!)
That may have been the case two decades ago, but it is not the case now.
C++ has looked far and wide for inspiration, and there is a good deal
of "language X can do /this/ in /that/ way - is that something C++
should copy?".