簡體   English   中英

C++ 線程安全切換字符串

[英]C++ thread safe switching over string

我有一長串字符串條件。 為了低延遲和代碼可讀性,我更喜歡使用 switch 而不是“else if”。 感謝評論,我編輯了這個問題並通過將字符串映射到 callable 來實現切換:

#include <unordered_map>
#include <iostream>
#include <functional>
#include <thread>

struct Message{
    Message(const std::string field_name, const std::string data) : m_FieldName(field_name), m_Data(data) {}
    const std::string m_FieldName;
    const std::string m_Data;
};

class Handler{
    static const std::unordered_map<std::string, std::function<void(const Message &)>> m_FieldNameCallback;

public:
    bool operator()(Message message){
        bool res = true;
        auto it = m_FieldNameCallback.find(message.m_FieldName);
        if(it != m_FieldNameCallback.cend()){
            it->second(message);
        }
        else{
            std::cout << "Invalid message with field name: " << message.m_FieldName <<"\n";
            res = false;
        }
        return res;
    }
};

const std::unordered_map<std::string, std::function<void(const Message &)>> Handler::m_FieldNameCallback = {
    {"BusinessAction", [](const Message & message){std::cout<< 5 << ": " << message.m_Data << "\n";}},
    {"BusinessClass", [](const Message & message){std::cout<< 6 << ": " << message.m_Data << "\n";}},
    //...
    {"PriceVariation", [](const Message & message){std::cout<< 695 << ": " << message.m_Data << "\n";}},
    {"PairedVolume", [](const Message & message){std::cout<< 698 << ": " << message.m_Data << "\n";}}
};

int main(){
    Handler h1;
    std::thread t1(h1, Message("BusinessAction", "&&&##@@@"));
    std::thread t2(h1, Message("BusinessClass", "&##@"));
    std::thread t3(h1, Message("Business", "&##@"));
    t1.join();
    t2.join();
    t3.join();
}

Handler 線程安全嗎? 使用現代 C++,有沒有更慣用的方法來切換字符串?

你肯定取得了很好的進步。 要么使映射成為靜態處理程序函數的非靜態成員。 現在我認為有一個奇怪的組合。 這里有一些我會做的稍微不同的事情,如果你有問題,請告訴我。

#include <unordered_map>
#include <iostream>
#include <functional>
#include <future>

struct Message
{
    Message(const std::string field_name, const std::string data) : m_FieldName(field_name), m_Data(data) {}

    const std::string m_FieldName;
    const std::string m_Data;
};

//---------------------------------------------------------------------------------------------------------------------

class Handler final // small tweak, no inheritance support (e.g. virtual methods/destructor)
{
    /*static*/ const std::unordered_map<std::string, std::function<void(const Message&)>> m_FieldNameCallback; 
    std::mutex m_output_mtx;

public:
    Handler() :
        m_FieldNameCallback
        {
            {"BusinessAction", [this](const Message& message) {show_message(5,message); }},
            {"BusinessClass", [this](const Message& message) {show_message(6,message); }},
            //...
            {"PriceVariation", [this](const Message& message) {show_message(695,message); }},
            {"PairedVolume", [this](const Message& message) {show_message(698,message); }}
        }
    {
    }

    bool operator()(const Message& message)  // pass by const ref, message should not change and ref will avoid copy
    {
        // I prefer exception based error handling, so an example of that  here.
        // also allows us to use at() instead of find
        try
        {
            // no lock needed since map is readonly
            auto callback = m_FieldNameCallback.at(message.m_FieldName);
            callback(message);
            return true;
        }
        catch (const std::out_of_range&)
        {
            show_invalid_message(message);
            return false;
        }
    }

private:
    void show_invalid_message(const Message& message)
    {
        std::unique_lock<std::mutex> lock(m_output_mtx);
        std::cout << "Invalid message with field name: " << message.m_FieldName << "\n";
    }

    void show_message(unsigned int number, const Message& message)
    {
        std::unique_lock<std::mutex> lock(m_output_mtx);
        std::cout << number << ": " << message.m_Data << "\n";
    }
};

int main()
{
    Handler handler;

    // async is a higher level abstraction then thread
    // it also allows you to get values calculated on other thread wiht future.get()
    // also any uncaught exceptions will be rethrown by get (allowing you to pass errors between threads)

    auto ft1 = std::async(std::launch::async, [&handler] { handler(Message{ "BusinessAction", "&&&##@@@" }); });
    auto ft2 = std::async(std::launch::async, [&handler] { handler(Message{ "BusinessClass", "&##@" }); });
    auto ft3 = std::async(std::launch::async, [&handler] { handler(Message{ "Business", "&##@" }); });

    ft1.get();
    ft2.get();
    ft3.get();

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM