Решение Alex Martelli будет работать для однопоточных приложений, но может не работать для многопоточных приложений, которым необходимо управлять количеством десятичных знаков в потоке. Вот решение, которое должно работать в многопоточных приложениях:
import threading
from json import encoder
def FLOAT_REPR(f):
"""
Serialize a float to a string, with a given number of digits
"""
decimal_places = getattr(encoder.thread_local, 'decimal_places', 0)
format_str = '%%.%df' % decimal_places
return format_str % f
encoder.thread_local = threading.local()
encoder.FLOAT_REPR = FLOAT_REPR
#As an example, call like this:
import json
encoder.thread_local.decimal_places = 1
json.dumps([1.56, 1.54]) #Should result in '[1.6, 1.5]'
Вы можете просто установить encoder.thread_local.decimal_places число нужных вам десятичных знаков и следующий вызов json.dumps () в этом потоке будет использоваться такое количество знаков после запятой
Откажитесь от подписки (), должно быть синхронным, так, чтобы это не возвращалось, пока Наблюдатель, как не гарантируют больше, не будет в списке Предмета. Это - единственный способ сделать это безопасно.
ETA (перемещающий мой комментарий в ответ):
Так как время, кажется, не проблема, не берет и не выпускает взаимное исключение между уведомлением каждого наблюдателя. Вы не сможете использовать for_each путем, Вы теперь, и необходимо будет проверить итератор, чтобы гарантировать, что это все еще допустимо.
for ( ... )
{
take mutex
check iterator validity
notify
release mutex
}
Это сделает то, что Вы хотите.
Можно ли измениться, подпись Подписывают () Отказывание от подписки ()? Замена The Observer* с чем-то как shared_ptr <Наблюдатель> сделала бы вещи легче.
Править: Замененный "легкий" "более легким" выше. Для примера того, как в этом трудно "разобраться", см. историю Повышения. Сигналы и Повышения adopted-but-not-yet-in-the-distribution. Signals2 (раньше Повышение. ThreadSafeSignals) библиотеки.
Вместо того, чтобы сделать, чтобы клиенты получили уведомление "SafeToDelete", предоставьте им IsSubscribed (Наблюдатель *) метод. Клиентский код затем становится:
subject.Unsubscribe( obsever );l
while( subject.IsSubscribed( observer ) ) {
sleep_some_short_time; // OS specific sleep stuff
}
delete observer;
который не слишком обременителен.
Вы могли создать "к - удаляют очередь" в типе CSubject. При удалении The Observer Вы могли назвать pSubject-> QueueForDelete (pObserver). Затем, когда подчиненный поток между уведомлениями, он мог безопасно удалить наблюдателей из очереди.
Mmm... Я действительно не понимаю Вашего вопроса, потому что, если клиент звонит, Отказываются от подписки, необходимо смочь позволить клиенту удалить его (он не используется Вами). Однако, если по некоторым причинам Вы не можете закрыть отношения, после того как клиент отказывается от подписки наблюдатель, Вы могли добавить "Предмет" новая операция для безопасного удаления Наблюдателя, или просто чтобы клиенты предупредили, что они больше не интересуются Наблюдателем.
Редактирование переосмысления: хорошо, теперь я думаю, что понимаю то, что является Вашей проблемой. Я думаю, что лучшее решение Вашей проблемы делает следующее:
Учитывая, что отказываться от подписки операция заблокируется на взаимном исключении для сброса допустимого флага (и что тот конкретный Наблюдатель не будет больше использоваться в потоке), код ориентирован на многопотоковое исполнение, и клиенты могут удалить любого наблюдателя, как только отказываются от подписки, возвратился.
Я думаю, что это добивается цели если не очень изящно:
class Subject {
public:
Subject() : t(bind(&Subject::Run, this)),m_key(0) { }
void Subscribe(Observer* o) {
mutex::scoped_lock l(m);
InternalObserver io( o );
boost::shared_ptr<InternalObserver> sp(&io);
observers.insert(pair<int,boost::shared_ptr<InternalObserver>> (MakeKey(o),sp));
}
void Unsubscribe(Observer* o) {
mutex::scoped_lock l(m);
observers.find( MakeKey(o) )->second->exists = false; }
void WaitForSomethingInterestingToHappen() {}
void Run()
{
for (;;)
{
WaitForSomethingInterestingToHappen();
for( unsigned int i = 0; i < observers.size(); ++ i )
{
mutex::scoped_lock l(m);
if( observers[i]->exists )
{
mem_fun(&Observer::Notify);//needs changing
}
else
{
observers.erase(i);
--i;
}
}
}
}
private:
int MakeKey(Observer* o) {
return ++m_key;//needs changeing, sha of the object?
}
class InternalObserver {
public:
InternalObserver(Observer* o) : m_o( o ), exists( true ) {}
Observer* m_o;
bool exists;
};
map< int, boost::shared_ptr<InternalObserver> > observers;
thread t;
mutex m;
int m_key;
};
Что-то вроде этого было бы удовлетворительно? Все еще не безопасно отказаться от подписки наблюдатель, будучи уведомленным, хотя, для которого Вам был бы нужен интерфейс как Вы упомянутый (насколько я могу сказать).
Subscribe(Observer *x)
{
mutex.lock();
// add x to the list
mutex.unlock();
}
Unsubscribe(Observer *x)
{
mutex.lock();
while (!ok_to_delete)
cond.wait(mutex);
// remove x from list
mutex.unlock();
}
NotifyLoop()
{
while (true) {
// wait for something to trigger a notify
mutex.lock();
ok_to_delete = false;
// build a list of observers to notify
mutex.unlock();
// notify all observers from the list saved earlier
mutex.lock();
ok_to_delete = true;
cond.notify_all();
mutex.unlock();
}
}
Если Вы хотите смочь Отказаться от подписки (), внутри Уведомляют () - (плохое проектное решение на клиенте IMO...), что можно добавить идентификатор потока потока notifier в структуру данных. В Отказываться от подписки функции можно проверить, что идентификатор потока против идентификатора текущего потока (большинство библиотек поточной обработки обеспечивает это - например, pthread_self). Если они - то же, можно продолжить двигаться, не ожидая на условной переменной.
Примечание: Если клиент ответственен за удаление наблюдателя, это означает столкновение с ситуацией, где в Уведомлять обратном вызове, Вы отпишете и удалите наблюдателя, но все еще выполняетесь, что-то с этим выбросило этот указатель. Это - что-то, о чем клиент должен будет знать и только удалить его в конце Уведомления ().