Задать вопрос
unclechu
@unclechu

Как работать с асихнронным кодом в C++ модуле для Node.JS?

В JS-коде биндится callback в глобальную область видимости, который потом нужно вызывать внутри C++ кода, который не связан с Node.JS и работает асинхронно через pthread, в отдельном потоке.

Упрощённо:
Persistent<Function> processCallback;

Handle<Value> bindProcess(const Arguments &args)
{
    HandleScope scope;

    if ( ! args[0]->IsFunction()) {
        ThrowException(Exception::TypeError(String::New("Callback argument must be a function")));
        return scope.Close(Undefined());
    }

    Local<Function> callback = Local<Function>::Cast( args[0] );
    processCallback = Persistent<Function>::New( callback );

    return scope.Close(Undefined());
}

int process()
{
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(123) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    return 0;
}

Проблема в том, что код в process, как ни крутил, — вываливается segfault-ом. Я явно что-то недопонимаю и делаю ошибку в архитектуре. Подскажите, как правильно это реализовать? Возможно нужно что-то делать через uv?

UPD: Проблема решилась после курения мануалов по libuv:
uv_work_t *baton;

void work(uv_work_t* task) {}

void after(uv_work_t* task, int status) {
    HandleScope scope;

    int n = *((int*)(&task->data));
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(n) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    scope.Close(Undefined());
    delete task;
}

int process()
{
    baton = new uv_work_t();
    baton->data = (void*)123;
    uv_queue_work(uv_default_loop(), baton, work, after);
    return 0;
}

Теперь проблема в том, что код вызова в process асинхронен, мне нужно внутри process дождаться выполнения after и только после этого продолжить. Как это сделать — это уже пожалуй другой топик.

UPD2: синхронность обеспечена через семафоры: Как синхронизировать libuv код?
  • Вопрос задан
  • 3170 просмотров
Подписаться 2 Оценить Комментировать
Решения вопроса 1
unclechu
@unclechu Автор вопроса
Решилось, правда не совсем так как хотелось. Теперь вызов коллбека асинхронен, но мне нужно получить результат внутри «process», хотябы просто дождаться завершения «after».
uv_work_t *baton;

void work(uv_work_t* task) {}

void after(uv_work_t* task, int status) {
    HandleScope scope;

    int n = *((int*)(&task->data));
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(n) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    scope.Close(Undefined());
    delete task;
}

int process()
{
    baton = new uv_work_t();
    baton->data = (void*)123;
    uv_queue_work(uv_default_loop(), baton, work, after);
    return 0;
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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