Как мне разорвать отношения наблюдателя в многопоточном C ++?

Решение 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 () в этом потоке будет использоваться такое количество знаков после запятой

11
задан fizzer 12 February 2009 в 04:36
поделиться

7 ответов

Откажитесь от подписки (), должно быть синхронным, так, чтобы это не возвращалось, пока Наблюдатель, как не гарантируют больше, не будет в списке Предмета. Это - единственный способ сделать это безопасно.

ETA (перемещающий мой комментарий в ответ):

Так как время, кажется, не проблема, не берет и не выпускает взаимное исключение между уведомлением каждого наблюдателя. Вы не сможете использовать for_each путем, Вы теперь, и необходимо будет проверить итератор, чтобы гарантировать, что это все еще допустимо.

for ( ... )
{
    take mutex
    check iterator validity
    notify
    release mutex
}

Это сделает то, что Вы хотите.

7
ответ дан 3 December 2019 в 08:05
поделиться

Можно ли измениться, подпись Подписывают () Отказывание от подписки ()? Замена The Observer* с чем-то как shared_ptr <Наблюдатель> сделала бы вещи легче.

Править: Замененный "легкий" "более легким" выше. Для примера того, как в этом трудно "разобраться", см. историю Повышения. Сигналы и Повышения adopted-but-not-yet-in-the-distribution. Signals2 (раньше Повышение. ThreadSafeSignals) библиотеки.

3
ответ дан 3 December 2019 в 08:05
поделиться

Вместо того, чтобы сделать, чтобы клиенты получили уведомление "SafeToDelete", предоставьте им IsSubscribed (Наблюдатель *) метод. Клиентский код затем становится:

subject.Unsubscribe( obsever );l
while( subject.IsSubscribed( observer ) ) {
   sleep_some_short_time;   // OS specific sleep stuff
}
delete observer;

который не слишком обременителен.

1
ответ дан 3 December 2019 в 08:05
поделиться

Вы могли создать "к - удаляют очередь" в типе CSubject. При удалении The Observer Вы могли назвать pSubject-> QueueForDelete (pObserver). Затем, когда подчиненный поток между уведомлениями, он мог безопасно удалить наблюдателей из очереди.

1
ответ дан 3 December 2019 в 08:05
поделиться

Mmm... Я действительно не понимаю Вашего вопроса, потому что, если клиент звонит, Отказываются от подписки, необходимо смочь позволить клиенту удалить его (он не используется Вами). Однако, если по некоторым причинам Вы не можете закрыть отношения, после того как клиент отказывается от подписки наблюдатель, Вы могли добавить "Предмет" новая операция для безопасного удаления Наблюдателя, или просто чтобы клиенты предупредили, что они больше не интересуются Наблюдателем.

Редактирование переосмысления: хорошо, теперь я думаю, что понимаю то, что является Вашей проблемой. Я думаю, что лучшее решение Вашей проблемы делает следующее:

  1. Каждый сохранил элемент наблюдателя, чтобы иметь "допустимый" флаг. Этот флаг будет использоваться для уведомления его или не, в то время как Вы находитесь в цикле уведомления.
  2. Вам нужно взаимное исключение для защиты доступа к тому "допустимому" флагу. Затем отказываться от подписки операция блокирует взаимное исключение для "допустимого" флага, устанавливает его на ложь для выбранного наблюдателя.
  3. Цикл уведомления также должен заблокировать и разблокировать взаимное исключение допустимого флага и только реагировать на наблюдателей, которые "допустимы".

Учитывая, что отказываться от подписки операция заблокируется на взаимном исключении для сброса допустимого флага (и что тот конкретный Наблюдатель не будет больше использоваться в потоке), код ориентирован на многопотоковое исполнение, и клиенты могут удалить любого наблюдателя, как только отказываются от подписки, возвратился.

1
ответ дан 3 December 2019 в 08:05
поделиться

Я думаю, что это добивается цели если не очень изящно:

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;
};
0
ответ дан 3 December 2019 в 08:05
поделиться

Что-то вроде этого было бы удовлетворительно? Все еще не безопасно отказаться от подписки наблюдатель, будучи уведомленным, хотя, для которого Вам был бы нужен интерфейс как Вы упомянутый (насколько я могу сказать).

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). Если они - то же, можно продолжить двигаться, не ожидая на условной переменной.

Примечание: Если клиент ответственен за удаление наблюдателя, это означает столкновение с ситуацией, где в Уведомлять обратном вызове, Вы отпишете и удалите наблюдателя, но все еще выполняетесь, что-то с этим выбросило этот указатель. Это - что-то, о чем клиент должен будет знать и только удалить его в конце Уведомления ().

1
ответ дан 3 December 2019 в 08:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: