Я сталкиваюсь с проблемой в программировании, когда я не нашел удобных и быстрых решений для выполнения.
Я пытаюсь реализовать какой-то конечный автомат: взять один байт в записи, обработать его, изменить состояние, цикл и т. Д. Цель состоит в том, чтобы обрабатывать поток байтов, не требуя буфера памяти (обработка байта на байт).
Класс должен выглядеть так:
class Decoder {
void next() {
int i = 0;
std::cout << i << "\n";
i++;
yield(); // pseudo code => should stop the function and save the current state (or simply not freeing allocated variables)
std::cout << i << "\n";
}
};
Decoder decoder = Decoder();
decoder.next(); // print 1
std::cout << "1.5" << "\n"; // print 1.5
decoder.next(); // print 2
Решением может быть создание step
свойство, чтобы сохранить шаг, а затем возобновить с переключателем, но производительность будет сильно затронута. Я хотел бы знать, если есть способ выйти из выполнения функции, а затем возобновить его позже?
Чтобы было ясно, я не хочу останавливать всю программу, только функцию. Приостановка такой функции вернет вызывающую программу и продолжит выполнение программы до следующего next
называется.
Кроме того, я хотел бы избежать как потока, так и стандартного ввода (я предпочитаю весь код среды). Наконец, если у вас есть другие альтернативы моей проблеме: эффективно обрабатывайте поток байтов для памяти, я открыт для ваших предложений.
Спасибо за вашу помощь.
Я считаю, что вы могли бы достичь этого, используя эти два способа:
Вариант 1: государство-член
Разделите объект конечного автомата на отдельный объект и преобразуйте все свои локальные переменные в члены.
Для каждого шага сохраните State
член, обозначающий, где вы сейчас находитесь на протяжении всего выполнения вашей программы.
Каждый раз, когда вы вводите next()
проверьте свое состояние с помощью переключателя и вызовите назначенный внутренний метод для этого шага.
Каждый такой метод шага имитирует выполнение кода между последовательными yields
,
struct Decoder {
void next() {
switch (_step) {
case s1:
step1();
_step = s2;
return;
case s2:
step2();
_step = s1;
return;
default:
return; // handle error...
}
}
private:
enum Step { s1, s2 };
Step _step = s1;
int _i = 1;
void step1() {
std::cout << _i << "\n";
_i++;
}
void step2() {
std::cout << _i << "\n";
}
};
int main() {
Decoder decoder = Decoder();
decoder.next(); // print 1
std::cout << "1.5" << "\n"; // print 1.5
decoder.next(); // print 2
}
Вариант 2: нить и сигнализация
Используйте поток, который вы, конечно, можете запускать с использованием нативных API (например, pthread_create на платформах POSIX).
Внутри вашей темы, каждый раз, когда вы хотите yield
дождитесь условной переменной, например:
struct Decoder {
Decoder() {
_thread = std::thread { &Decoder::worker, this };
}
~Decoder() {
_thread.join();
}
void next() {
std::lock_guard<std::mutex> lock(_mutex);
_work = true;
}
private:
void wait() {
std::unique_lock<std::mutex> lock(_mutex);
_cond.wait(lock, [this](){return _work;});
}
void worker() {
wait();
int i = 0;
std::cout << i << "\n";
i++;
wait();
std::cout << i << "\n";
}
std::thread _thread;
std::mutex _mutex;
std::condition_variable _cond;
bool _work = false;
};
int main() {
Decoder decoder;
decoder.next(); // print 1
std::cout << "1.5" << "\n"; // print 1.5
decoder.next(); // print 2
}
Других решений пока нет …