Project

General

Profile

Feature #142

Improve threadsafety

Added by John Abbott about 12 years ago. Updated 3 months ago.

Status:
In Progress
Priority:
Normal
Assignee:
-
Category:
Safety
Target version:
Start date:
30 Apr 2012
Due date:
% Done:

50%

Estimated time:
Spent time:

Description

Currently CoCoALib can be made (largely?) threadsafe by compiling with the flag -DCoCoA_THREADSAFE_HACK. As its name suggests it is a hack rather than a proper solution to the problem.

This hack involves disabling memory allocation by MemPool by #defining MemPool to be MemPoolFake which simply forwards all requests to the C++ memory manager (::operator new and ::operator delete).

The hack also disables reference counting, so all ref counted objects live forever. Naturally this causes some memory leaks (see issue #141).


Related issues

Related to CoCoA - Bug #141: Memory leak using Elim in C5Closed2012-04-30

Related to CoCoALib - Feature #157: Separate ThreadsafeCounter from symbol.CClosed2012-05-10

Related to CoCoALib - Bug #413: OrdvArith: use of a single buffer is NOT THREADSAFEClosed2013-11-21

Related to CoCoALib - Bug #784: threadsafety: Scott Meyers's advice about cached valuesIn Progress2015-10-12

Related to CoCoALib - Design #787: Remove refcounts from RingElem?New2015-10-16

Related to CoCoALib - Feature #835: Make Mario's new code threadsafeNew2015-12-09

Related to CoCoALib - Design #1259: ThreadsafeCounter is now obsolete?Closed2019-03-25

Related to CoCoALib - Design #1225: Move to C++14 (skipping C++11)In Progress2018-09-06

Related to CoCoALib - Bug #1522: SEGV: avoid long linked lists of loaves in MemPoolsClosed2020-10-26

History

#1 Updated by John Abbott about 12 years ago

If ref counting is removed (seems to be highly desirable to avoid it in multithreaded programs) then CoCoALib needs to be told when to destroy rings. This implies making an important change to the interface to the class ring. Two likely additions are:
  • an RAII class for "local" rings
  • an explicit "destroy" command for rings

#2 Updated by Anna Maria Bigatti about 12 years ago

John Abbott wrote:

No doubt the problem is due to the temporary rings (inside Elim) not self destroying when they're no longer needed -- ref counting is disabled when the threadsafety hack is forced.

Elim (and a few other functions) create a temporary ring.
I think we should have a way to destroy a (temporary) ring to be called at the end of the function. In fact it would do nothing when ref counting is on (just check it is really destroyable).
The only danger is that inside a child call a global variable (bad for thread-safety anyway) is defined, is that correct?

#3 Updated by John Abbott about 12 years ago

Anna Maria Bigatti wrote:

Elim (and a few other functions) create a temporary ring.

Yes. Temporary rings are a common idiom. It would be nice to have an easy way of handling them correctly (probably via RAII).

I think we should have a way to destroy a (temporary) ring to be called at the end of the function. In fact it would do nothing when ref counting is on (just check it is really destroyable).

This is what the RAII approach should do.

The only danger is that inside a child call a global variable (bad for thread-safety anyway) is defined, is that correct?

Anna clarified this last comment: the "danger" is that an incautious programmer could leave an element of the temporary ring in a global variable, which would then lead to "undefined behaviour" when that global is altered. The solution is easy: don't use globals :-)

#4 Updated by Anna Maria Bigatti over 11 years ago

  • Category set to Safety

#5 Updated by John Abbott over 10 years ago

  • Status changed from New to In Progress
  • % Done changed from 0 to 50

#6 Updated by Anna Maria Bigatti over 10 years ago

  • Target version set to CoCoALib-0.99533 Easter14

#7 Updated by John Abbott about 10 years ago

  • Target version changed from CoCoALib-0.99533 Easter14 to CoCoALib-0.99534 Seoul14

#8 Updated by John Abbott almost 10 years ago

  • Target version changed from CoCoALib-0.99534 Seoul14 to CoCoALib-1.0

#9 Updated by John Abbott almost 9 years ago

I wonder whether the default configuration for CoCoALib should be the threadsafe one (which incurs a run-time efficiency penalty).

Currently the default is not threadsafe.

What do you think?

#10 Updated by John Abbott over 8 years ago

After looking around on internet it seems that C++98 has no portable way of dealing with threadsafety, but C++11 (and later versions) does.

Probably the "threadsafe hack" should be migrated to a proper threadsafe option, presumably controlled by a pre-compilation flag CoCoA_THREADSAFE. This implies that default compilation (without setting that flag) would be only single-threaded. Setting the option also implies that compilation is of C++11.

#11 Updated by John Abbott over 8 years ago

I spoke to Mario this morning about threadsafety in CoCoALib (also thinking about Mario's new code which has just been adjoined to the CVS repository).

Mario liked the idea of a single flag, tentatively called CoCoA_THREADSAFE, which when set will produce threadsafe code (but which also requires a C++11 compiler); if the flag is not set then the resulting executable is not guaranteed to be threadsafe, but it should be possible to compile with a C++03 compiler (for the time being).

Comments? Suggestions? Other ideas?

#12 Updated by John Abbott over 8 years ago

I wonder whether CoCoA_THREADSAFE is to be just a temporary measure. Presumably at some point practically all compilers will accept C++11. The main question would then be whether the threadsafety measures incur a significant run-time cost during single-threaded execution; if not, then presumably the preprocessor flag will no longer serve any useful purpose (except perhaps for obfuscated code competitions?).

#13 Updated by John Abbott over 5 years ago

  • Related to Design #1259: ThreadsafeCounter is now obsolete? added

#14 Updated by John Abbott over 4 years ago

  • Related to Design #1225: Move to C++14 (skipping C++11) added

#15 Updated by John Abbott over 3 years ago

I now think that it is probably better to default to threadsafe code; the user must configure with "not threadsafe" to obtain (presumably faster) non-threadsafe compilation.

Note that when releasing CoCoA-5 we can opt for the "fast, not threadsafe" compilation since CoCoA-5 itself is single-threaded.

If we do follow this proposal, what should the "not threadsafe" option be called?

#16 Updated by John Abbott over 3 years ago

I changed SmartPtrIRC so that an std::atomic<std::size_t> is used for the ref count instead of std::size_t.
I tried just one speed test:
  • non-threadsafe took about 14.7s to run all the tests in src/tests/
  • threadsafe took about 16.1s

So for this 1 test suite, threadsafe was about 10% slower.

I would expect that some computations with many ring elems in a small finite field could incur a significantly greater overhead.
So it is likely worth offering a way to compile non-threadsafe code.

The source files which must be checked are:
  • MemPool, OrdvArith, SmartPtrIRC, NumTheory-prime.C, PPMonoidOV.C

Rectifying NumTheory-prime.C might be time-consuming (currently it is unsafe).

#17 Updated by John Abbott over 3 years ago

  • Target version changed from CoCoALib-1.0 to CoCoALib-0.99850
I propose the following new names:
  • --allow-non-threadsafe for the configure script
  • CoCoA_ALLOW_NON_THREADSAFE as the corresponding CPP identifier

There is a potentially non-obvious dependency: to use MemPool memory mgt, you must allow non-threadsafe compilation.
This means that unless CoCoA_ALLOW_NON_THREADSAFE is defined, MemPool will actually refer to MemPoolFake (which just forwards all requests to operator new)

#18 Updated by John Abbott over 3 years ago

  • Related to Bug #1522: SEGV: avoid long linked lists of loaves in MemPools added

#19 Updated by John Abbott 3 months ago

  • Target version changed from CoCoALib-0.99850 to CoCoALib-0.99880

Also available in: Atom PDF