Monday, August 10, 2009

Secret sauce revealed

In my previous post, I showed a little program using stackless coroutines with asio. Obviously there's no yield keyword in C++, so without further ado here's the preprocessor magic that makes it possible:

class coroutine
{
public:
coroutine() : value_(0) {}
private:
friend class coroutine_ref;
int value_;
};

class coroutine_ref
{
public:
coroutine_ref(coroutine& c) : value_(c.value_) {}
coroutine_ref(coroutine* c) : value_(c->value_) {}
operator int() const { return value_; }
int operator=(int v) { return value_ = v; }
private:
int& value_;
};

#define reenter(c) \
switch (coroutine_ref _coro_value = c)

#define entry \
extern void you_forgot_to_add_the_entry_label(); \
bail_out_of_coroutine: break; \
case 0

#define yield \
if ((_coro_value = __LINE__) == 0) \
{ \
case __LINE__: ; \
(void)&you_forgot_to_add_the_entry_label; \
} \
else \
for (bool _coro_bool = false;; \
_coro_bool = !_coro_bool) \
if (_coro_bool) \
goto bail_out_of_coroutine; \
else

Unlike the preprocessor-based coroutines presented here, the above macros let you yield from a coroutine without having to return from a function. Instead, the yield simply breaks you out of the reenter block. That trick is what allows us to write a server in one function.

Yes, yes, I know. An echo server in a single function is a bit of a gimmick. The following snippet may give a better idea of how the coroutines can be used:

class session : coroutine
{
public:
session(tcp::acceptor& acceptor)
: acceptor_(acceptor),
socket_(new tcp::socket(acceptor.get_io_service())),
data_(new array<char, 1024>)
{
}

void operator()(
error_code ec = error_code(),
size_t length = 0)
{
reenter (this)
{
entry:
for (;;)
{
yield acceptor_.async_accept(
*socket_, *this);

while (!ec)
{
yield socket_->async_read_some(
buffer(*data_), *this);

if (ec) break;

yield async_write(*socket_,
buffer(*data_, length), *this);
}

socket_->close();
}
}
}

private:
tcp::acceptor& acceptor_;
shared_ptr<tcp::socket> socket_;
shared_ptr<array<char, 1024> > data_;
};

Compared to the usual boost::bind-based approach of doing callbacks, the control flow is all in one place and easy to follow.

But wait, there's more... In the next post I'll reveal the real power you get when you combine stackless coroutines and asio.

27 comments:

Marat Abrarov said...

Question:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void operator()(
error_code ec = error_code(),
size_t length = 0)
{
int a = 0;

reenter (this)
{
entry:
for (;;)
{
yield acceptor_.async_accept(
*socket_, *this);

a = 1;

while (!ec)
{
yield socket_->async_read_some(
buffer(*data_), *this);

// what is a here?
a = 1;

if (ec) break;

yield async_write(*socket_,
buffer(*data_, length), *this);

// what is a here?
a = 2;

}

socket_->close();
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I think "a" at question places will always be 0. Am I right?

chris said...

That's correct. If you want your coroutine to have "local" variables, you should make them data members of the function object.

Unknown said...

That's interesting...

I wanted easier program flow usage, and didn't want to embed a scripting language (yet). So I wrapped it up in a macro ("CREATE_CALLBACK")..

http://pastebin.ca/1538834

Instead of deriving my class, Application::Main, from it, I pass it a an argument. Not really the same as a coroutine, but the point was the same ("the control flow is all in one place and easy to follow"). I find using Asio a lot easier this way. Any suggestions?

Thanks again for Asio!

Unknown said...

BTW I'm still debugging that code, it's nasty, but gets the point across.

chris said...

@Daemn: Looks like you would like C++0x lambdas then. However, I'm a little confused: don't your macros create local classes? What compiler are you using, because (pre-C++0x) you can't use local classes as template parameters.

Eric Muyser said...

I will like C++0x lambdas when we get to that point. Until then..

No the first argument is just the name of the local class. Second argument is the main class all the callbacks are inside, simply because 'this' pointer changes. Can't access variables outside the inner scopes, so boxing/unboxing named variable list. Really shotty, but it seems to work. It's like extremely verbose ActionScript/JavaScript function objects (usually used as callbacks).

Eric Muyser said...

@chris I ran into the local class used as a template argument error today. Good call. I -was- using Visual Studio VC9, and now I'm using MinGW.

Unknown said...

You should explain how those macros work. There seem to be many "tricks" that are useful but aren't required to make coroutines work.

For example, it *seems* to me that the for loop inside 'yield' is just a trick to execute something *after* the yield expression while not making yield use function syntax.

Similarly for you_forgot_to_add_the_entry_label. I suspect it would be easier to follow if you remove the "feature" of: giving a readable warning if you forget the entry label.

Maybe show it as a tutorial for creating such a macro. Start simple, then add the tricks one by one...

Anonymous said...

Perhaps user error, but in VC9 this sample seems to build in Debug but not in Release. An attempt at a release build causes a link error for 'you_forgot_to_add_the_entry_label' despite the fact that the code builds and runs with a debug build.

Dave Abrahams said...
This comment has been removed by the author.
Anonymous said...

Chris - is there supposed to be another "case __LINE__:;" so you can jump back after the yield?

You have that case statement only if __LINE__ is 0 ie.,((_coro_value = __LINE__)==0).

How will it jump back to the line after the yield next time?

Gryffin said...

This coroutine does it for yield! Wow. https://healthybodyhealthymind.com/vigrx-plus/

BIG BOSS said...

and sharing. I wish you good luck with your website in the future and you can be sure I'll be following it.
Took me time to understand all of the comments, but I seriously enjoyed the write-up. It proved being really helpful to me and Im positive to all of the Good post, adding it to my blog now, thanks. >
am sure. to everyone posting comments! It's not often that you can be informed, and also entertained at the same time. I am certain you also got something out of I will top 520 UK local citations listing and for local SEO sites

casinositeone.JDS said...

everyone an extremely breathtaking chance to read from this blog. It is always so lovely and jam-packed with a great time. 카지노사이트원

casinosite777info.JDS said...

Excellent goods from you, man. I have understand your stuff previous to and you are just extremely excellent. 카지노사이트

casinositezone.JDS said...


It’s always a pleasure to read your magnificent articles on this site. You are among the top writers of this generation, and there’s nothing you can do that will change my opinion on that. 카지노사이트

casinositeguidecom.JDS said...

My friends will soon realize how good you are. Feel free to visit my website;
바카라사이트

Dijital Pazarlamacilar said...

SEO Nedir

Arama motoru optimizasyonu nedir?
Arama motoru optimizasyonu, insanlar ürün veya hizmet aradığında görünürlüğünü artırmak için bir web sitesini iyileştirme bilimidir. Bir web sitesinin arama motorlarında ne kadar görünürlüğü olursa, markanın iş yakalama olasılığı o kadar artar.

Web sitesi görünürlüğü genellikle sitenin arama motoru sonuç sayfalarındaki (SERP'ler) yerleşimi veya sıralaması ile ölçülür. Ve şirketler her zaman en çok dikkati çekecekleri ilk sayfa için rekabet ederler.

Google'ı örnek olarak kullanırsak, SERP'ler genellikle sayfanın üst kısmında reklamlara yer verir. Bunlar, işletmelerin ilk sayfada yer almasını sağlamak için ödemeye hazır oldukları pozisyonlardır. Aşağıdaki reklamlar, pazarlamacıların ve arama motorlarının organik arama sonuçları olarak adlandırdığı normal arama listeleridir. SEO süreci, bir işletmenin organik arama sonuçlarını artırmayı ve siteye organik arama trafiği çekmeyi amaçlar. Bu, veri pazarlamacılarının bir web sitesine diğer kanallardan (ücretli arama, sosyal medya , yönlendirmeler ve doğrudan) gelen trafik ile organik arama trafiği arasında ayrım yapmalarını sağlar .

Organik arama trafiği genellikle daha yüksek kaliteli trafiktir çünkü kullanıcılar bir sitenin sıralanabileceği belirli bir konuyu, ürünü veya hizmeti aktif olarak ararlar. Bir kullanıcı bu siteyi arama motoru aracılığıyla bulursa, daha iyi marka etkileşimi sağlayabilir.

SEO nasıl çalışır?
Sonuçları en üst düzeye çıkarmanın bir yolu olsa da, arama algoritmalarını tamamen manipüle etmek neredeyse imkansızdır . İşletmeler genellikle en az çabayla ideal sonuçlara giden en kısa yolu arar, ancak SEO çok fazla eylem ve zaman gerektirir. Yarın net sonuçlar beklentisiyle bugün bir şeylerin değiştirilebileceği bir SEO stratejisi yoktur. SEO, günlük eylem ve sürekli aktivite ile uzun vadeli bir projedir.

Arama motorları, tüm web sitesi sayfalarını taramak, bu bilgileri bir dizin olarak bilinen bir koleksiyona indirmek ve depolamak için botları kullanır. Bu dizin bir kütüphane gibidir ve birisi içinde bir şey aradığında arama motoru kütüphaneci gibi davranır. Arama motoru, arama sorgusundan ilgili bilgileri alır ve görüntüler ve kullanıcılara aradıkları şeyle ilgili içeriği gösterir. Arama motoru algoritmaları, bu sayfaların SERP'de görüntülenmesi gereken sırayı belirlemek için dizindeki web sayfalarını analiz eder.

Arama motoru optimizasyonu nasıl çalışır grafiği
İşte arama motoru optimizasyonunun nasıl çalıştığına dair kısa bir açıklama.
Arama motoru optimizasyonu için hangi algoritmalar değerlendirilir?
Dizinden hangi içeriğin bir SERP'de görüntüleneceğini belirleyen yüzlerce faktör vardır. Ancak, bir arama sorgusu için hangi sonuçların döndürüleceğini belirlemeye yardımcı olan beş temel faktöre ayrılırlar.

sportstotomen com said...


wow, its a incredible information. thanks for sharing.
안전놀이터

gostopsite said...


I must thank you for the efforts you’ve put in writing this blog.
섯다

19guide03 said...

Excellent and nice post. It will beneficial for everyone.
일본야동

Toya Schlabaugh said...

For those who wants to sign up your youngster, with the greatest educators, we provide tutoring and personal tutoring expert services within Jabodetabek ... visit https://bimbel-calistung.netlify.app/les-privat-calistung-tanah-abang.html for further

Adina Feight said...

Executive-Education.id is an experienced private tutoring institution in Jabodetabek as well as surroundings that can bring students with the best teachers ... go to https://privatmurah.vercel.app/les-privat-kemang-murah.html for more information

StevenGreen said...

In today's fast-paced and ever-changing business landscape, companies must find ways to increase efficiency and reduce costs while maintaining high-quality services. A wide range of services rom basic data entry to complex accounting services, the team have the expertise to handle any task efficiently and effectively. And that`s not all the benefits of such type of remote cooperation. Use this link and navigate to this site!

RFincher said...

Driverless innovation and ethereal conveyance drones are opening new entryways for independent dispersion. DHL is trying self-driving trucks, Google dispatches its driverless vehicles to beat Amazon Prime in same-date conveyance.

Most tech firms offer custom retail programming improvement changing the answer for the particular requirements of an organization. Today retail tech modernization frequently includes new retail bookkeeping programming, electronic answers for web based business, simulated intelligence controlled apparatuses for client information observing, client chatbots, request satisfaction robotization, face acknowledgment advances, and so on>> retail software development

Theon said...

It was practical. Keep posting!

Xavier said...

Thanks sharing excellent info