C / C ++ с вызываемыми сопрограммами? - PullRequest
2 голосов
/ 14 сентября 2011

Кажется, что сопрограммы обычно встречаются на языках более высокого уровня.

wikipedia / en / wiki / Coroutine

Кажется, есть несколько различных определений их какЧто ж.Я пытаюсь отыскать специально вызываемые сопрограммы в Си, как в Lua.

 function foo()     
     print("foo", 1) 
     coroutine.yield() 
     print("foo", 2) 
 end 

Спасибо за чтение - Патрик

Ответы [ 4 ]

2 голосов
/ 14 сентября 2011

Нет поддержки уровня языка для сопрограмм ни в C, ни в C ++.

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

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

1 голос
/ 02 мая 2013

В библиотеке Boost C ++ появилась новая (начиная с версии 1.53.0) библиотека сопрограмм: http://www.boost.org/doc/libs/1_53_0/libs/coroutine/doc/html/index.html

Я не знаю о библиотеке C - я наткнулся на этот вопрос в поисках.

1 голос
/ 14 сентября 2011

Извините - ни C, ни C ++ не поддерживают сопрограммы. Тем не менее, простой поиск "C сопрограммы: дает следующий увлекательный трактат по проблеме: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html,, хотя вы можете найти его решение немного - гм - непрактично

0 голосов
/ 11 июля 2013

Есть куча сопрограммных библиотек для C ++. Вот один от RethinkDB.

Также есть моя библиотека только для заголовков , которая предназначена для использования с обратными вызовами. Я пробовал Boost сопрограммы , но пока не использую их из-за несовместимости с valgrind . Моя реализация использует ucontext.h и пока отлично работает под valgrind.

Со «стандартными» сопрограммами вы должны прыгать через несколько обручей, чтобы использовать их с обратными вызовами. Например, вот как выглядит работающий потокобезопасный (но текущий) обработчик чероки с сопрограммами Boost:

typedef coroutine<void()> coro_t;
auto lock = make_shared<std::mutex>();
coro_t* coro = new coro_t ([handler,buffer,&coro,lock](coro_t::caller_type& ca)->void {
  p1: ca();  // Pass the control back in order for the `coro` to initialize.
  coro_t* coro_ = coro;  // Obtain a copy of the self-reference in order to call self from callbacks.
  cherokee_buffer_add (buffer, "hi", 2); handler->sent += 2;
  lock->lock();  // Prevents the thread from calling the coroutine while it still runs.
  std::thread later ([coro_,lock]() {
    //std::this_thread::sleep_for (std::chrono::milliseconds (400));
    lock->lock();  // Wait for the coroutine to cede before resuming it.
    (*coro_)();  // Continue from p2.
  }); later.detach();
  p2: ca();  // Relinquish control to `cherokee_handler_frople_step` (returning ret_eagain).
  cherokee_buffer_add (buffer, ".", 1); handler->sent += 1;
});
(*coro)(); // Back to p1.
lock->unlock(); // Now the callback can run.

а вот как это выглядит у меня:

struct Coro: public glim::CBCoro<128*1024> {
  cherokee_handler_frople_t* _handler; cherokee_buffer_t* _buffer;
  Coro (cherokee_handler_frople_t *handler, cherokee_buffer_t* buffer): _handler (handler), _buffer (buffer) {}
  virtual ~Coro() {}
  virtual void run() override {
    cherokee_buffer_add (_buffer, "hi", 2); _handler->sent += 2;
    yieldForCallback ([&]() {
      std::thread later ([this]() {
        //std::this_thread::sleep_for (std::chrono::milliseconds (400));
        invokeFromCallback();
      }); later.detach();
    });
    cherokee_buffer_add_str (_buffer, "."); _handler->sent += 1;
  }
};
...