Having a hundred threads doing I/O at the same time is bad on magnetic disks because of the excessive disk seeks. So allow only 4 threads to copy closures in parallel.
MB3TISH2KYBIGY6XJKMN4HO2S6TCN2GORJENMECCKLXGGIRS2O2AC 5LBMP7GAY5IIOX75M62BRGKXS4BNIQRDBCYLM4PHI773KRABTL2QC 7LB6QBXYOGU43UDLJDJQZFGT4XDALULXDF3WX3WWHL7X3JTB54CQC 5AIYUMTBY6TFQTBRP3MJ2PYWUMRF57I77NIVWYE74UMEVQMBWZVQC OCZ4LSGGSCMSLGC3C32D5JUYYHS5CIPOKOAMADEFAFZOFXJ3YY3AC HHOMBU7GGRAEXODSDY3WUHQGOSQ35OTGRNBWKKAS2D4YEIZTTNUAC ENXUSMSVOU3AZFMH2ZXR4ZVPV2LRRQYQJ6IFX33YN6IH2ORSNSAAC 24BMQDZAWDQ7VNIA7TIROXSOYLOJBNZ2E4264WHWNJAEN6ZB3UOAC RYTQLATYOZ6ODIKYVJ63TC4OIQBXHSCV3NA2YD4NFP7443GQVSRQC /* Ensure that only a limited number of threads can copy closuresat the same time. However, proceed anyway after a timeout toprevent starvation by a handful of really huge closures. */time_t start = time(0);int timeout = 60 * (10 + rand() % 5);auto token(copyClosureTokenServer.get(timeout));time_t stop = time(0);if (token())printMsg(lvlDebug, format("got copy closure token after %1%s") % (stop - start));elseprintMsg(lvlDebug, format("dit not get copy closure token after %1%s") % (stop - start));
#pragma once#include <atomic>#include "sync.hh"/* This class hands out tokens. There are only ‘maxTokens’ tokensavailable. Calling get() will return a Token object, representingownership of a token. If no token is available, get() will sleepuntil another thread returns a token. */class TokenServer{unsigned int maxTokens;Sync<unsigned int> curTokens{0};std::condition_variable_any wakeup;public:TokenServer(unsigned int maxTokens) : maxTokens(maxTokens) { }class Token{friend TokenServer;TokenServer * ts;bool acquired = false;Token(TokenServer * ts, unsigned int timeout) : ts(ts){auto curTokens(ts->curTokens.lock());while (*curTokens >= ts->maxTokens)if (timeout) {if (!curTokens.wait_for(ts->wakeup, std::chrono::seconds(timeout),[&]() { return *curTokens < ts->maxTokens; }))return;} elsecurTokens.wait(ts->wakeup);(*curTokens)++;acquired = true;}public:Token(Token && t) : ts(t.ts) { t.ts = 0; }Token(const Token & l) = delete;~Token(){if (!ts || !acquired) return;{auto curTokens(ts->curTokens.lock());assert(*curTokens);(*curTokens)--;}ts->wakeup.notify_one();}bool operator ()() { return acquired; }};Token get(unsigned int timeout = 0){return Token(this, timeout);}};