Pass context through composed promises in KJ - c++

Playing with the KJ library, I wrote a small TCP servers that reads a "PING" and responds a "PONG". I managed to compose the promises like this:
char buffer[4];
kj::Own<kj::AsyncIoStream> clientStream;
addr->listen()->accept()
.then([&buffer, &clientStream](kj::Own<kj::AsyncIoStream> stream) {
clientStream = kj::mv(stream);
return clientStream->tryRead(buffer, 4, 4);
}).then([&buffer, &clientStream](size_t read) {
KJ_LOG(INFO, kj::str("Received", read, " bytes: ", buffer));
return clientStream->write("PONG", 4);
}).wait(waitScope);
I had to keep buffer out of the promises and pass a reference to it. This means that buffer has to stay in scope until the last promise finishes. That's the case here, but is there a solution in case it isn't?
Same thing for clientStream: I had to declare it before, then wait until I receives it from accept(), and at this point move it outside and use the reference to it.
Is there a better way to do it? Say like a way to pass some kind of context from promise to promise, always owned by the promises and therefore not having to stay "outside"?

It seems your problem is that your second lambda wants access to the scope of the first lambda, but the way you've organised things prevents that. You've worked around that by just adding variables to their shared "global" scope.
Instead, you could put the second lambda inside the first, something like this:
addr->listen()->accept()
.then([](kj::Own<kj::AsyncIoStream> stream) {
auto buffer = kj::heapArray<char>(4);
auto promise = stream->tryRead(buffer.begin(),4,4);
return promise.then([stream=kj::mv(stream), buffer=kj::mv(buffer)] (size_t read) mutable {
KJ_LOG(INFO, kj::str("Received", read, " bytes: ", buffer));
return stream->write("PONG", 4);
});
}).wait(waitScope);

Related

What does this size_t in the lambda do? C++ code

I'm new to programming in C++, and I came across this syntax. Could someone explain the point of the size_t in this syntax?
// Close the file stream.
.then([=](size_t)
{
return fileStream->close();
});
It's the type of the argument passed to the function. The argument is not used in the function. Hence, it is not named. Only the type of the argument is there.
The type of the argument is there presumably because the client to which the lambda expression is passed expects it to have an argument of type size_t. The client has no way of knowing how the argument is used in the lambda expression or whether it is used at all.
This is like callbacks where your callback receive data from the caller and you do whatever you want with the data .
So if you don't need the data you can skip naming the parameter as it's unreferenced
You can see more examples about callbacks by reading the documentation of some winapi functions especially which enum things . e.g EnumWindows , EnumChildWindows EnumProc ....
As others have said, the lambda expression
[=](size_t)
{
return fileStream->close();
}
is being passed to a method call
.then()
To shed some additional light: usually, a method called .then() is part of a Futures callback interface. The then() method is called on a Future<T> object, where T is some type. It will expect a callback parameter. This causes callback chaining: when the Future<T> is fulfilled, we will have a T, and at this point in time the callback is invoked with that T.
In your case, T = size_t. So presumably, the Future object that .then() is called on returns a size_t, which is then passed to the lambda [=] (size_t) { ... }. The lambda then discards the size_t because it doesn't need it.
What's the point of taking the size_t parameter if it doesn't need it? Well, maybe the original Future object was some kind of read call, and it stored the result somewhere else (i.e. the work is done by side-effect) and returned the number of bytes it read (the size_t). But the callback is just doing some cleanup work and doesn't care about what was read. It would be like the following synchronous code:
size_t readFile(char* buf) {
// ... store stuff in buf
return bytesRead;
}
auto closeFileStream(size_t) {
return fileStream->close();
}
closeFileStream(readFile(&buf));
In terms of Futures, it's probably something more like:
Future<size_t> readFile(char* buf) {
// ... asynchronously store stuff in buf
// and return bytesRead as a Future
}
auto closeFileStream(size_t) {
return fileStream->close();
}
readFile(&buf)
.then(closeFileStream)
.get(); // wait synchronously

C++ weird async behaviour

Note that I'm using boost async, due to the lack of threading classes support in MinGW.
So, I wanted to send a packet every 5 seconds and decided to use boost::async (std::async) for this purpose.
This is the function I use to send the packet (this is actually copying to the buffer and sending in the main application loop - nvm - it's working fine outside async method!)
m_sendBuf = new char[1024]; // allocate buffer
[..]
bool CNetwork::Send(const void* sourceBuffer, size_t size) {
size_t bufDif = m_sendBufSize - m_sendInBufPos;
if (size > bufDif) {
return false;
}
memcpy(m_sendBuf + m_sendInBufPos, sourceBuffer, size);
m_sendInBufPos += size;
return true;
}
Packet sending code:
struct TestPacket {
unsigned char type;
int code;
};
void SendPacket() {
TestPacket myPacket{};
myPacket.type = 10;
myPacket.code = 1234;
Send(&TestPacket, sizeof(myPacket));
}
Async code:
void StartPacketSending() {
SendPacket();
std::this_thread::sleep_for(std::chrono::seconds{5});
StartPacketSending(); // Recursive endless call
}
boost::async(boost::launch::async, &StartPacketSending);
Alright. So the thing is, when I call SendPacket() from the async method, received packet is malformed on the server side and the data is different than specified. This doesn't happend when called outside the async call.
What is going on here? I'm out of ideas.
I think I have my head wrapped around what you are doing here. You are loading all unsent in to buffer in one thread and then flushing it in a different thread. Even thought the packets aren't overlapping (assuming they are consumed quickly enough), you still to synchronize all the shared data.
m_sendBuf, m_sendInPos, and m_sendBufSize are all being read from the main thread, likely while memcpy or your buffer size logic is running. I suspect you will have to use a proper queue to get your program to work as intended in the long run, but try protecting those variables with a mutex.
Also as other commenters have pointed out, infinite recursion is not supported in C++, but that probably does not contribute to your malformed packets.

Garbage values in lambda-captured variables as callback

I know that this may be fairly confusing, but I'm writing a unit test using the Boost test framework. I'm trying to simply increment a variable to test that a specific callback was executed as expected.
This is the test code excerpt:
uint32_t nSuccessCallbacks = 0;
uint32_t nFailureCallbacks = 0;
auto successCallback = [&nSuccessCallbacks, this] {
std::cout << "Running success callback...\n";
++nSuccessCallbacks;
};
auto failureCallback = [&nFailureCallbacks, this] (const std::string& str) {
std::cout << "Error code: " << str << "\n";
std::cout << "Running failure callback...\n";
++nFailureCallbacks;
};
dest.advertise(rr, successCallback, failureCallback);
The definition of advertise:
void
NfdRibReadvertiseDestination::advertise(nfd::rib::ReadvertisedRoute& rr,
std::function<void()> successCb,
std::function<void(const std::string&)> failureCb)
{
m_controller.start<ndn::nfd::RibRegisterCommand>(
ControlParameters().setName(rr.getPrefix()).setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT).setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT),
[&] (const ControlParameters& cp) { successCb(); },
[&] (const ControlResponse& cr) { failureCb(cr.getText()); });
}
Just for reference, dest is defined in the test fixture.
I'm not able to modify nSuccessCallbacks. Whenever the callback is called, we step through it correctly, but after the callback exits and we are in code after dest.advertise(), the value is still 0. We successfully reach the callback lambda, but the gdb reports that there is no such variable in the scope. I've tried every reasonable combination of all-capture, specific capture, mixing in the this and removing it, etc. I don't know why the capture clause incorrectly captures the variable. My best guess is that since the lambda is passed into another lambda, the capture clause of the first is lost?
EDIT: The callback is executed when an interface object receives data. We mock that up later in the test, and was unimportant so I chose not to include it.
Using a crystal ball, your lambda is run after one of the many scopes where you capture something by reference (either advertise or your "test code exerpt") has exited. Thus the by-reference captured variable has left scope, and UB results, and you see garbage.
Your code as posted does not actually run the lambda, so clearly the code as posted has no such problem with the lambda containing garbage.
As a general rule, never capture by reference if your lambda or any copies of it could possibly outlive the current scope. Capture by copy, or (in C++14) by move. There are exceptions to this rule, but they are easy sources of bugs.
As a second rule, if your lambda outlives the current scope, explicitly capture everything you capture. Have no default capture. That way you won't be surprised by something being captured whose lifetime (or pointed-to lifetime) is not long enough, like this or some pointer or somesuch.
At the least do this:
[successCb] (const ControlParameters& cp) { successCb(); },
[failureCb] (const ControlResponse& cr) { failureCb(cr.getText()); }
Then ensure that this, and no copies of this:
auto successCallback = [&nSuccessCallbacks, this] {
std::cout << "Running success callback...\n";
++nSuccessCallbacks;
};
does not outlive its scope. If it does, change how you capture.
The start call will, given the name, start an asynchronous thread to process the request. Unfortunately this means that the variables captured by reference in the lambda will have been already deallocated when they're accessed.
C++ only allows you to capture by copy (and you've no lifetime problems) or to capture by reference but you must ensure that the lambda will not outlive the referenced variables.
To solve correctly the "upward funarg" problem (a lambda capturing a variable - not a value - from a context and outliving the context) a garbage collector is needed (a stack isn't enough) and C++ doesn't provide one.
A solution (if you pay attention to avoiding loops) is to capture by value a shared_ptr to the mutable shared state needed.

Passing messages between threads and memory management

I'm writing a C++ application with two threads. Thread A will send messages to thread B. The message type could be:
struct MyMessageType
{
int a;
enum MyEnum b;
bool someFlag;
}
A std::queue<MyMessageType> messageQueue is shared between the threads for passing messages.
In the sending thread, I'll have something like:
struct MyMessageType newMessage;
newMessage.a = 14;
newMessage.b = someEnumeratedValue;
newMessage.someFlag = false;
GrabTheMutexProtectingTheQueue();
messageQueue.push(newMessage);
ReleaseTheMutexProtectingTheQueue();
My question is regarding memory management, and is twofold:
A) How do I ensure that the pointer to newMessage is valid when the receiving thread gets the message? What would happen, for instance, if the function that created newMessage ended and newMessage therefore went out of scope before the receiving thread processed the message?
B) Once I can ensure that the newMessage pointer is valid when the receiving thread processes it, how to I free up the memory that was used by the struct?
The std::queue push() function stores a copy of whatever you give it (see here), so you don't have to worry about it going out of scope.
The copy in the queue will survive until you delete it with pop().
So, on the sending side, it's a simple matter of (for example):
lock_mutex();
myqueue.push (something);
unlock_mutex();
// Do whatever you want with something, the queue has a copy
and, at the receiving end:
lock_mutex();
while (myqueue.empty()) {
unlock_mutex();
// possibly yield to another thread
lock_mutex();
}
something = myqueue.front();
weaveMagicWith (something);
myqueue.pop();
unlock_mutex();
Of course, you can re-engineer that to minimise the duration of the mutex lock on the receiving end (if, for example, weaving magic takes a long time), it's just a rough example showing one way to do it.

winsock, message oriented networking, and type-casting the buffer from recv

Okay, I actually don't have code as of yet because i'm just picking out a framework for the time being, but i'm still a little baffled about how i wish to go about this :.
Server side, i wish to have a class where each instance has a socket and various information identifying each connection. each object will have it's own thread for receiving data. I understand how i'll be implementing most of that, but my confusion starts just as i get to the actual transfer of data between server and client. I'll want to have a bunch of different message structs for specific cases, (for example CONNECT_MSG , DISCONNECT_MSG, POSTTEXT_MSG, etc) and then all i have to do is have a char * point at that struct and then pass it via the send() function.
But as i think on it, it gets a little complicated at that point. Any of those different message types could be sent, and on the receiving end, you will have no idea what you should cast the incoming buffer as. What i was hoping to do is, in the thread of each connection object, have it block until it receives a packet with a message, then dump it into a single queue object managed by the server(mutexes will prevent greediness) and then the server will process each message in FIFO order independent of the connection objects.
I havn't written anything yet, but let me write a little something to illustrate my setup.
#define CONNECT 1000
struct GENERIC_MESSAGE
{
int id;
}
struct CONNECT_MESSAGE : public GENERIC_MESSAGE
{
m_username;
}
void Connection::Thread()
{
while(1)
{
char buffer[MAX_BUFFER_SIZE]; // some constant(probably 2048)
recv(m_socket, buffer, MAX_BUFFER_SIZE, 0);
MESSAGE_GENERIC * msg = reinterpret_cast<MESSAGE_GENERIC *> (buffer);
server->queueMessage(msg);
}
}
void Server::QueueMessage(MESSAGE_GENERIC * msg)
{
messageQueue.push(msg);
}
void Server::Thread()
{
while(1)
{
if(!messageQueue.empty())
ProcessMessages();
else
Sleep(1);
}
}
void Server::ProcessMessages()
{
for(int i = 0; i < messageQueue.size(); i++)
{
switch(messageQueue.front()->id)
{
case CONNECT:
{
// the part i REALLY don't like
CONNECT_MESSAGE * msg = static_cast<CONNECT_MESSAGE *>(messageQueue.front() );
// do the rest of the processing on connect
break;
}
// other cases for the other message types
}
messageQueue.pop();
}
}
Now if you've been following up until now, you realize just how STUPID and fragile this is. it casts to the base class, passes that pointer to a queue, and then just assumes that the pointer is still valid from the other thread, and even then whether or not the remaining buffer after the pointer for the rest of the derived class will always be valid afterward for casting, but i have yet to find a correct way of doing this. I am wide open for ANY suggestions, either making this work, or an entirely different messaging design.
Before you write even a line of code, design the protocol that will be used on the wired. Decide what a message will consist of at the byte level. Decide who sends first, whether messages are acknowledged, how receivers identify message boundaries, and so on. Decide how the connection will be kept active (if it will be), which side will close first, and so on. Then write the code around the specification.
Do not tightly associate how you store things in memory with how you send things on the wire. These are two very different things with two very different sets of requirements.
Of course, feel free to adjust the protocol specification as you write the code.