Синхронизация связывания Python и C

Я работаю над реализацией привязок Python для моей библиотеки C в реальном времени. Я читал, что потоки в Python не являются реальными потоками и что они на самом деле не работают параллельно (из-за глобальной блокировки интерпретатора). Тем не менее, мне пришлось бы рассмотреть следующую ситуацию.

Представьте себе следующую функцию C:

int stoppable_lock(mutex *m, bool *stop)
{
    while (!stop || !*stop)
        if (timed_lock(m, SOME_TIME) == SUCCESS)
            return SUCCESS;
    return DIDNT_LOCK;
}

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

Моя проблема состоит в том, чтобы выяснить, как написать оболочку Python для этой функции. Разбор аргументов (с PyArg_ParseTupleЯ могу восстановить мьютекс, нет проблем. Тем не менее, тип объектов, которые могут быть отправлены в функцию, выглядит как строки, числа и объекты. Первые два, очевидно, не могут заменить bool *и я сомневаюсь писать обертку для bool * хорошая идея

У меня вопрос, как я могу получить параметр, который является ссылкой на переменную (совместно используемую с другими потоками Python), а не просто его копию?

Вот функция с частью, которую я пропускаю (для использования как mutex.stoppable_lock(stop)):

static PyObject *_stoppable_lock(_mutex *obj, PyObject *args)
{
    int ret;
    BOOL_STAR stop;
    if (!PyArg_ParseTuple(args, "?", &stop))
    {
        PyErr_SetString(PyExc_ValueError, "Usage: mutex.stoppable_lock(BOOL_STAR)");
        return NULL;
    }
    ret = stoppable_lock(obj->orig, stop);
    if (_set_exception(ret))
        return NULL;
    Py_RETURN_NONE;
}

Где мне неизвестно что BOOL_STAR а также "?" должно быть.

3 ответа

Решение

Вам нужно создать тип оболочки для bool, с функциями мутатора Python для встроенного значения. Если вы хотите избежать создания своего собственного типа, и если вы уверены, что C _Bool совпадает с C++ bool, то вы можете использовать ctypes.c_bool. Сценарий Python может затем сделать

   stop = ctypes.c_bool(False)
   stoppable_lock(mutex, ctypes.addressof(stop))

а другой поток мог тогда сделать stop.value = True, Модуль расширения будет ожидать long, а затем приведёт это к указателю. Если вы хотите, чтобы это было более безопасно для типов, вам нужно создать свой собственный тип оболочки для bool.

Потоки Python - это реальные потоки (по крайней мере, в CPython для большинства серверных реализаций потоков). Но вы правы, потому что благодаря GIL сам код Python никогда не выполняется параллельно, хотя многие функции (особенно IO) подойдут.

Относительно вашего основного вопроса: Если вы хотите напрямую следовать логике реализации C (имея ссылку на bool), NPE уже сказал это: вы можете заключить его в изменяемый объект, например:

class MutableBool:
    value = False

В противном случае весь код stoppable_lock также может быть легко переопределено в Python, и тогда оно может стать более простым.

У меня вопрос, как я могу получить параметр, который является ссылкой на переменную (совместно используемую с другими потоками Python), а не просто его копию?

Вы могли бы обернуть stop в изменяемом объекте и передать ссылку на этот объект.

Другие вопросы по тегам