Boost Websockets "mutex lock failed" when implementing using static methods

  boost, boost-beast, c++, multithreading

The Problem

I am trying to create a websocket to connect to a fairly busy server feed using C++ and Boost::Beast. For now, all it does is read the data, decode it in a weird way, and print it out.

I have the setup done, but for some reason when I change my socket setup to use static methods and variables in my connection class, it gives this weird error:

libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument

What I’ve Done So Far

Looking up this issue online, multiple threads seem to hint that this is a multithreading issue. The thing is… my software is single-threaded.

All it does so far is the following:

main.cpp

#include "OkexSocket.h"

int main() {
    const std::string host = "real.okex.com";
    auto const port  = "8443";
    auto const path  = "/ws/v3";
    OkexSocket::init_socket(host, port, path);

    OkexSocket::send_subscribe(R"({"op": "subscribe", "args": ["swap/depth_l2_tbt:ETH-USDT-SWAP","swap/depth_l2_tbt:BTC-USDT-SWAP"]})");
    OkexSocket::receive_data();
}

and here is how i implemented these functions:

First i create the websocket connection in OkexSocket::init_socket, and store the stream for later use:

void OkexSocket::init_socket(const string& host, const string& port, const string& path) {
        net::io_context ioc;
        tcp::resolver resolver{ ioc };

        ssl::context ctx { ssl::context::sslv23 };
        ctx.set_verify_mode(ssl::verify_none);

        auto* socket = new websocket::stream<ssl::stream<tcp::socket>>{ioc, ctx };

        net::connect(beast::get_lowest_layer(*socket), resolver.resolve(host, port));

        // SSL handshake
        socket->next_layer().handshake(ssl::stream_base::client);

        socket->handshake(host + ":" + port, path);
        socket_logger->info("Client is connected...");
        OkexSocket::s = socket;
}

I then call the OkexSocket::send_subscribe which is basically a one-liner:

void OkexSocket::send_subscribe(const string &message) {
    // send request to the websocket
    s->write(net::buffer(message));
}

and then I feed in the stream of data as so:

void OkexSocket::receive_data() {
    std::vector<uint8_t> in, out;
    auto in_buffer = net::dynamic_buffer(in);
    int i = 0;
    while (true) {
        socket->read(in_buffer);
        
        // decode and print in_buffer...

        in_buffer.consume(in_buffer.size());
        if (i++ == 300) {
            break;
        }
    }
}

Notes and Takeaways…

  • yes i know there is a memory leak, with the OkexSocket::s. I don’t really care about it since it needs to exist for the life of the program and is only initialized once. Since the system will reclaim that space after the code is done, i shouldn’t care tbh. Open for criticism on code structure though.

  • If you add all this code into main() it works just fine… no clue why

I am fairly new to boost::beast and tbh, I haven’t found much resources to help with this :/
I honestly think the documentation assumes someone who is a pro in boost and networking, which sadly I am not. If all you can provide is resources to help me, I would love that so much.

Source: Windows Questions C++

LEAVE A COMMENT