безопасность потоков в тридцати библиотеках - PullRequest
0 голосов
/ 18 апреля 2011


Я хочу использовать библиотеку, разработанную кем-то другим, у меня есть только файл библиотеки, а не исходный код.У меня такой вопрос: библиотека предоставляет класс с рядом функций.Сам класс не является потокобезопасным.Я хотел сделать это потокобезопасным, и мне было интересно, если этот код работает

// suppose libobj is the class provided by the library
class my_libobj : public libobj {
   // code
};

Ответы [ 4 ]

3 голосов
/ 18 апреля 2011

Это наследуется только от libobj, который может или не может "работать" в зависимости от того, был ли класс предназначен для наследования (имеет по крайней мере virtual деструктор).

В любом случае, это не купит вам безопасность потоков бесплатно. Самый простой способ добиться этого - добавить мьютексы в класс и заблокировать их при входе в критическую секцию:

class my_obj {
    libobj obj;  // inheritance *might* work too
    boost::mutex mtx;

    void critical_op()
    {
        boost::unique_lock lck(mtx);
        obj.critical_op();
    }
};

(Это очень грубый дизайн с одним мьютексом; вы можете сделать его более детальным, если знаете поведение различных операций. Он также не защищен от ошибок, как объясняет @dribeas.)

2 голосов
/ 18 апреля 2011

Модернизация безопасности потоков - и кстати, есть разные уровни - в библиотеке, для которой она не предназначена, вероятно, невозможно без знания того, как она реализована, если вы не довольны простой сериализацией all вызывает его, и даже тогда это может быть проблематично, если интерфейс достаточно плохой - см., Например, strtok.

1 голос
/ 18 апреля 2011

Самое простое решение состоит в том, чтобы создать отдельный поток для этой библиотеки уникальным образом и обращаться к библиотеке только из этого потока, используя очереди сообщений для передачи запросов и возврата параметров.

1 голос
/ 18 апреля 2011

На это невозможно ответить без знания хотя бы фактического интерфейса класса.В общем случае ответ будет отрицательным.

С практической точки зрения C ++, если класс не предназначен для расширения, каждый не виртуальный метод не будет переопределен, и в результате вы можете получить смесь из некоторых поточно-безопасных и некоторыхметоды, не поддерживающие потоки.

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

Рассмотрим реализацию stack, как в STL, просто добавив слой блокировки (т.е. сделав каждый метод потокобезопасным, выне будет гарантировать безопасность потоков в контейнере. Рассмотрим несколько потоков, добавляющих элементы в стек, и два потока, извлекающих информацию:

if ( !stack.empty() ) {  // 1
   x = stack.top();      // 2
   stack.pop();          // 3
   // operate on data
}

Существует ряд возможных вещей, которые могут пойти не так: здесь могут выполняться оба потокапроверить [1], когда в стеке есть один элемент, а затем ввести последовательно, в этом случае второй поток завершится с ошибкой в ​​[2] (или получить то же значение и потерпеть неудачу в [3]), даже в случае несколькихобъекты в контейнере, оба потока могут выполнить [1] и [2] до того, как любой из них выполнит [3], и в этом случае оба потока будут использовать один и тот же объект, а второй элемент в стеке будет отброшен без обработки...

Безопасность потоков требует (в большинстве случаев) изменений в API, в exaНесколько выше, интерфейс, который обеспечивает bool pop( T& v );, реализованный как:

bool stack::try_pop( T& v ) {     // argument by reference, to provide exception safety
   std::lock<std:mutex> l(m);
   if ( s.empty() ) return false; // someone consumed all data, return failure
   v = s.top();                   // top and pop are executed "atomically"
   s.pop();
   return true;                   // we did consume one datum
}

Конечно, есть и другие подходы, вы можете не возвращать ошибку, а скорее ждать условия в операции pop, которая гарантированноблокировка до тех пор, пока данные не будут готовы, используя условную переменную или что-то подобное ...

...