編集:「関数を事前/事後待機部分に分割」したくないと述べています。
どの言語で開発していますか? 継続がある場合 ( yield return
C# の場合)、手続き型のように見えるが、ブロック操作が完了コールバックを行うまで簡単に一時停止できるコードを記述する方法が提供されます。
このアイデアに関する記事は次のとおりです: http://msdn.microsoft.com/en-us/magazine/cc546608.aspx
アップデート:
残念ながら、言語は C++ です。
それは素晴らしいTシャツのスローガンになるでしょう.
シーケンシャル コードをステート マシンとして構造化すると、割り込み/再開が可能になります。
たとえば、あなたの痛みは、開始する関数と完了イベントのハンドラーとして機能する関数の 2 つの関数を記述する必要があります。
void send_greeting(const std::string &msg)
{
std::cout << "Sending the greeting" << std::endl;
begin_sending_string_somehow(msg, greeting_sent_okay);
}
void greeting_sent_okay()
{
std::cout << "Greeting has been sent successfully." << std::endl;
}
あなたのアイデアは待つことでした:
void send_greeting(const std::string &msg)
{
std::cout << "Sending the greeting" << std::endl;
waiter w;
begin_sending_string_somehow(msg, w);
w.wait_for_completion();
std::cout << "Greeting has been sent successfully." << std::endl;
}
その例では、waiter
operator() をオーバーロードして、コールバックとして機能できるようにwait_for_completion
し、operator() が呼び出されたことを確認するまで何らかの方法でハングアップします。
begin_sending_string_somehow
の2番目のパラメーターは、パラメーターを受け入れない呼び出し可能な型にすることができるテンプレートパラメーターであると想定しています。
しかし、おっしゃる通り、これには欠点があります。スレッドがそのように待機しているときはいつでも、別の潜在的なデッドロックを追加し、スレッド全体とそのスタックの「リソース」も消費しています。つまり、作業を実行できるようにするために、別の場所でより多くのスレッドを作成する必要があります。 、これはスレッドプールの要点と矛盾しています。
代わりに、クラスを作成します。
class send_greeting
{
int state_;
std::string msg_;
public:
send_greeting(const std::string &msg)
: state_(0), msg_(msg) {}
void operator()
{
switch (state_++)
{
case 0:
std::cout << "Sending the greeting" << std::endl;
begin_sending_string_somehow(msg, *this);
break;
case 1:
std::cout << "Greeting has been sent successfully."
<< std::endl;
break;
}
}
};
このクラスは、関数呼び出し operator を実装します()
。呼び出されるたびに、ロジックの次のステップが実行されます。(もちろん、些細な例であるため、これはほとんどが状態管理のノイズですが、4 つまたは 5 つの状態を持つより複雑な例では、コードのシーケンシャルな性質を明確にするのに役立つ場合があります)。
問題:
イベント コールバック関数のシグネチャに特別なパラメーターがある場合はoperator()
、追加のフィールドにパラメーターを格納し、パラメーターなしのオーバーロードを呼び出す の別のオーバーロードを追加する必要があります。これらのフィールドは、初期状態での実行時には意味がなくても、初期状態ではコンパイル時にアクセスできるため、その後、乱雑になり始めます。
クラスのオブジェクトはどのように構築および削除されますか? オブジェクトは、操作が完了するか放棄されるまで存続する必要があります... C++ の中心的な落とし穴です。それを管理するための一般的なスキームを実装することをお勧めします。「削除する必要があるもの」のリストを作成し、これが特定の安全なポイントで自動的に行われるようにします。つまり、できる限り GC に近づけるようにします。そこから離れれば離れるほど、より多くのメモリがリークします。