Make Encoding class thread-safe

Now all const methods may be called without additional locking.
This is assumed by the threaded LaTeX export, which always useses a globally
unique instance for each encoding.
This commit is contained in:
Georg Baum 2014-12-08 22:25:40 +01:00
parent 364e0f72c4
commit c6b98a504f
2 changed files with 35 additions and 12 deletions

View File

@ -19,6 +19,7 @@
#include "support/debug.h"
#include "support/gettext.h"
#include "support/lstrings.h"
#include "support/mutex.h"
#include "support/textutils.h"
#include "support/unicode.h"
@ -105,10 +106,28 @@ Encoding::Encoding(string const & n, string const & l, string const & g,
void Encoding::init() const
{
// Since the the constructor is the only method which sets complete_
// to false the test for complete_ is thread-safe without mutex.
if (complete_)
return;
start_encodable_ = 0;
static Mutex mutex;
Mutex::Locker lock(&mutex);
// We need to test again for complete_, since another thread could
// have set it to true while we were waiting for the lock and we must
// not modify an encoding which is already complete.
if (complete_)
return;
// We do not make any member mutable so that it can be easily verified
// that all const methods are thread-safe: init() is the only const
// method which changes complete_, encodable_ and start_encodable_, and
// it uses a mutex to ensure thread-safety.
CharSet & encodable = const_cast<Encoding *>(this)->encodable_;
char_type & start_encodable = const_cast<Encoding *>(this)->start_encodable_;
start_encodable = 0;
// temporarily switch off lyxerr, since we will generate iconv errors
lyxerr.disable();
if (fixedwidth_) {
@ -122,10 +141,10 @@ void Encoding::init() const
char_type const uc = ucs4[0];
CharInfoMap::const_iterator const it = unicodesymbols.find(uc);
if (it == unicodesymbols.end())
encodable_.insert(uc);
encodable.insert(uc);
else if (!it->second.force()) {
if (forced_->empty() || forced_->find(uc) == forced_->end())
encodable_.insert(uc);
encodable.insert(uc);
}
}
} else {
@ -138,10 +157,10 @@ void Encoding::init() const
if (!eightbit.empty()) {
CharInfoMap::const_iterator const it = unicodesymbols.find(c);
if (it == unicodesymbols.end())
encodable_.insert(c);
encodable.insert(c);
else if (!it->second.force()) {
if (forced_->empty() || forced_->find(c) == forced_->end())
encodable_.insert(c);
encodable.insert(c);
}
}
}
@ -149,11 +168,11 @@ void Encoding::init() const
lyxerr.enable();
CharSet::iterator it = encodable_.find(start_encodable_);
while (it != encodable_.end()) {
encodable_.erase(it);
++start_encodable_;
encodable.erase(it);
++start_encodable;
it = encodable_.find(start_encodable_);
}
complete_ = true;
const_cast<Encoding *>(this)->complete_ = true;
}

View File

@ -109,7 +109,11 @@ private:
};
///
/**
* An encoding as defined in lib/encodings.
* All const methods are thread-safe, so the caller does not need any locking.
* This property must be kept when changing the class.
*/
class Encoding {
public:
/// Which LaTeX package handles this encoding?
@ -195,13 +199,13 @@ private:
typedef std::set<char_type> CharSet;
/// Set of UCS4 characters that we can encode (for singlebyte
/// encodings only)
mutable CharSet encodable_;
CharSet encodable_;
/// Set of UCS4 characters that we can't encode
CharSet const * forced_;
/// All code points below this are encodable. This helps us to avoid
/// lokup of ASCII characters in encodable_ and gives about 1 sec
/// speedup on export of the Userguide.
mutable char_type start_encodable_;
char_type start_encodable_;
/// Which LaTeX package handles this encoding?
Package package_;
/**
@ -211,7 +215,7 @@ private:
* This is needed especially for the multibyte encodings, if we
* complete all encoding info on startup it takes 2-3 minutes.
*/
mutable bool complete_;
bool complete_;
};
class Encodings {