Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+;中的活动对象模式示例有什么问题+;? #包括 #包括 #包括 #包括 #包括 #包括 #包括 向量函数; 枚举函数代码{ 退出=-1,通知=0,打印 }; 类消息 { 公众: int代码; std::任何数据; }; 无效执行功能(常量消息和消息){ 返回函数[message.code](message.data); } 名称空间X{ 类消息队列 { 好友类线程; 类节点 { 公众: 节点(MessageQueue::Node*next,MessageQueue::Node*prev,const Message&Message) :next(next)、prev(prev)、message(message){ 私人: 节点*下一步; 节点*prev; 信息; 好友类消息队列; }; 节点*头,*尾; std::互斥互斥; std::条件变量cv; 公众: MessageQueue(Node*head,Node*tail):head(head),tail(tail){} MessageQueue():MessageQueue(nullptr,nullptr){} 无效推送(常量消息和消息) { { std::锁和保护锁(互斥锁); 自动新建节点=新建节点(尾部、空PTR、消息); 如果(!tail){ 尾=头=新节点; }否则{ tail->prev=新建_节点; tail=新的_节点; } } cv.通知_one(); } 消息弹出() { std::唯一锁(互斥锁); wait(lock,[this](){return(bool)head;}); 自动头\u至\u删除=头; 自动消息=头部->消息; 如果(头部->上一个){ head->prev->next=nullptr; } head=head->prev; 如果(!头){ tail=nullptr; } 删除标题_至_删除; 返回消息; } }; 类线程 { 标准:螺纹; 公众: 消息队列; 线程():队列(nullptr,nullptr), 线程([此](){ while(true){ 自动消息=queue.pop(); 如果(message.code==退出){ 打破 } 执行_功能(消息); } }) {} void join(){thread.join();} ~Thread(){if(Thread.joinable())Thread.join();} }; } 螺纹打印机; 线程通知程序; void cout(const std::string和text){ 静态std::mutex cout_mutex; std::锁定保护(cout_mutex); 标准::cout n; 而(n--){ //为什么打印不正确?。。 std::字符串文本; std::cin>>文本; std::any data=std::move(文本); 推送通知(std::移动(数据)); } 退出_线程(); 连接_线程(); }_C++_Multithreading_Synchronization_Message Queue_Race Condition - Fatal编程技术网

C++ C+;中的活动对象模式示例有什么问题+;? #包括 #包括 #包括 #包括 #包括 #包括 #包括 向量函数; 枚举函数代码{ 退出=-1,通知=0,打印 }; 类消息 { 公众: int代码; std::任何数据; }; 无效执行功能(常量消息和消息){ 返回函数[message.code](message.data); } 名称空间X{ 类消息队列 { 好友类线程; 类节点 { 公众: 节点(MessageQueue::Node*next,MessageQueue::Node*prev,const Message&Message) :next(next)、prev(prev)、message(message){ 私人: 节点*下一步; 节点*prev; 信息; 好友类消息队列; }; 节点*头,*尾; std::互斥互斥; std::条件变量cv; 公众: MessageQueue(Node*head,Node*tail):head(head),tail(tail){} MessageQueue():MessageQueue(nullptr,nullptr){} 无效推送(常量消息和消息) { { std::锁和保护锁(互斥锁); 自动新建节点=新建节点(尾部、空PTR、消息); 如果(!tail){ 尾=头=新节点; }否则{ tail->prev=新建_节点; tail=新的_节点; } } cv.通知_one(); } 消息弹出() { std::唯一锁(互斥锁); wait(lock,[this](){return(bool)head;}); 自动头\u至\u删除=头; 自动消息=头部->消息; 如果(头部->上一个){ head->prev->next=nullptr; } head=head->prev; 如果(!头){ tail=nullptr; } 删除标题_至_删除; 返回消息; } }; 类线程 { 标准:螺纹; 公众: 消息队列; 线程():队列(nullptr,nullptr), 线程([此](){ while(true){ 自动消息=queue.pop(); 如果(message.code==退出){ 打破 } 执行_功能(消息); } }) {} void join(){thread.join();} ~Thread(){if(Thread.joinable())Thread.join();} }; } 螺纹打印机; 线程通知程序; void cout(const std::string和text){ 静态std::mutex cout_mutex; std::锁定保护(cout_mutex); 标准::cout n; 而(n--){ //为什么打印不正确?。。 std::字符串文本; std::cin>>文本; std::any data=std::move(文本); 推送通知(std::移动(数据)); } 退出_线程(); 连接_线程(); }

C++ C+;中的活动对象模式示例有什么问题+;? #包括 #包括 #包括 #包括 #包括 #包括 #包括 向量函数; 枚举函数代码{ 退出=-1,通知=0,打印 }; 类消息 { 公众: int代码; std::任何数据; }; 无效执行功能(常量消息和消息){ 返回函数[message.code](message.data); } 名称空间X{ 类消息队列 { 好友类线程; 类节点 { 公众: 节点(MessageQueue::Node*next,MessageQueue::Node*prev,const Message&Message) :next(next)、prev(prev)、message(message){ 私人: 节点*下一步; 节点*prev; 信息; 好友类消息队列; }; 节点*头,*尾; std::互斥互斥; std::条件变量cv; 公众: MessageQueue(Node*head,Node*tail):head(head),tail(tail){} MessageQueue():MessageQueue(nullptr,nullptr){} 无效推送(常量消息和消息) { { std::锁和保护锁(互斥锁); 自动新建节点=新建节点(尾部、空PTR、消息); 如果(!tail){ 尾=头=新节点; }否则{ tail->prev=新建_节点; tail=新的_节点; } } cv.通知_one(); } 消息弹出() { std::唯一锁(互斥锁); wait(lock,[this](){return(bool)head;}); 自动头\u至\u删除=头; 自动消息=头部->消息; 如果(头部->上一个){ head->prev->next=nullptr; } head=head->prev; 如果(!头){ tail=nullptr; } 删除标题_至_删除; 返回消息; } }; 类线程 { 标准:螺纹; 公众: 消息队列; 线程():队列(nullptr,nullptr), 线程([此](){ while(true){ 自动消息=queue.pop(); 如果(message.code==退出){ 打破 } 执行_功能(消息); } }) {} void join(){thread.join();} ~Thread(){if(Thread.joinable())Thread.join();} }; } 螺纹打印机; 线程通知程序; void cout(const std::string和text){ 静态std::mutex cout_mutex; std::锁定保护(cout_mutex); 标准::cout n; 而(n--){ //为什么打印不正确?。。 std::字符串文本; std::cin>>文本; std::any data=std::move(文本); 推送通知(std::移动(数据)); } 退出_线程(); 连接_线程(); },c++,multithreading,synchronization,message-queue,race-condition,C++,Multithreading,Synchronization,Message Queue,Race Condition,在这里,我有3个线程。主线程、通知程序线程和打印机线程。这是多余的,但仅用于示例 在这里,主线程将一条消息推送到通知程序的队列中,告诉它通知打印机打印。然后,通知程序将一条消息推送到队列中,通知打印机打印 这里,如果我输入3abc(全部在一行中),则输出为零。但是,如果我一个接一个地输入,它会打印除最后一个之外的所有内容 打印除最后一个之外的所有内容的情况可能是因为每个输入和下一个输入之间存在时间延迟 为什么会发生这种情况?在正常情况下,主线程只与通知程序通信,然后通知程序与打印机通信。但对于退

在这里,我有3个线程。主线程、通知程序线程和打印机线程。这是多余的,但仅用于示例

在这里,主线程将一条消息推送到通知程序的队列中,告诉它通知打印机打印。然后,通知程序将一条消息推送到队列中,通知打印机打印

这里,如果我输入
3abc
(全部在一行中),则输出为零。但是,如果我一个接一个地输入,它会打印除最后一个之外的所有内容

打印除最后一个之外的所有内容的情况可能是因为每个输入和下一个输入之间存在时间延迟


为什么会发生这种情况?

在正常情况下,主线程只与通知程序通信,然后通知程序与打印机通信。但对于退出,主线程直接与通知程序和打印机通信

这意味着可以在通知程序向打印机队列发送之前将退出消息添加到打印机队列。因此,考虑到这些操作:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <functional>
#include <any>
#include <condition_variable>

std::vector<std::function<void(std::any)>> functions;

enum FunctionCodes {
    EXIT = -1, NOTIFY = 0, PRINT
};

class Message
{
public:
    int code;
    std::any data;
};

void perform_function(const Message& message) {
    return functions[message.code](message.data);
}

namespace X {

    class MessageQueue
    {
        friend class Thread;

        class Node
        {
        public:
            Node(MessageQueue::Node *next, MessageQueue::Node *prev, const Message& message)
                : next(next), prev(prev), message(message) {}

        private:
            Node* next;
            Node* prev;
            Message message;
            friend class MessageQueue;
        };

        Node *head, *tail;
        std::mutex mutex;
        std::condition_variable cv;

    public:

        MessageQueue(Node *head, Node *tail) : head(head), tail(tail) {}
        MessageQueue() : MessageQueue(nullptr, nullptr) {}

        void push(const Message& message)
        {
            {
                std::lock_guard<std::mutex> lock(mutex);
                auto new_node = new Node(tail, nullptr, message);
                if (!tail) {
                    tail = head = new_node;
                } else {
                    tail->prev = new_node;
                    tail = new_node;
                }
            }
            cv.notify_one();
        }

        Message pop()
        {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, [this](){ return (bool)head; });
            auto head_to_delete = head;
            auto message = head->message;
            if (head->prev) {
                head->prev->next = nullptr;
            }
            head = head->prev;
            if (!head) {
                tail = nullptr;
            }
            delete head_to_delete;
            return message;
        }
    };

    class Thread
    {
        std::thread thread;
    public:
        MessageQueue queue;
        Thread() : queue(nullptr, nullptr),
            thread([this]() {
                while (true) {
                    auto message = queue.pop();
                    if (message.code == EXIT) {
                        break;
                    }
                    perform_function(message);
                }
            }) {}
        void join() { thread.join(); }
        ~Thread() { if (thread.joinable()) thread.join(); }
    };
}

X::Thread printer;
X::Thread notifier;

void cout(const std::string& text) {
    static std::mutex cout_mutex;
    std::lock_guard<std::mutex> guard(cout_mutex);
    std::cout << text << '\n';
}

void push_notify(std::any data) {
    notifier.queue.push({NOTIFY, std::move(data)} );
}

void notify(std::any data) {
    printer.queue.push({PRINT, std::move(data)});
}

void print(std::any data) {
    cout(std::any_cast<std::string>(std::move(data)));
}

void init_functions() {
    functions.resize(2);
    functions[NOTIFY] = notify;
    functions[PRINT] = print;
}

void exit_threads() {
    printer.queue.push({EXIT, {}});
    notifier.queue.push({EXIT, {}});
}

void join_threads() {
    printer.join();
    notifier.join();
}

int main()
{
    init_functions();

    int n;
    std::cin >> n;

    while (n--) {
        // FIXME why doesn't it print correctly?..
        std::string text;
        std::cin >> text;
        std::any data = std::move(text);
        push_notify(std::move(data));
    }

    exit_threads();
    join_threads();
}
打印机队列看起来像
a、b、EXIT、c
。它在打印
c
之前退出。如果在一行中输入所有输入,情况会更糟,因为主线程能够在通知程序向打印机发送任何内容之前将出口发送到打印机

解决方案是让
exit_threads
函数只向通知程序发送消息。当通知程序看到退出消息时,应将其转发到打印机并中断。确保发送到通知程序的所有消息在退出之前发送到打印机:

main sends 'a' to notifier
main sends 'b' to notifier
main sends 'c' to notifier
notifier sends 'a' to printer
notifier sends 'b' to printer
main sends EXIT to notifier
main sends EXIT to printer
notifier sends 'c' to printer

在正常情况下,主线程仅与通知程序通信,通知程序随后与打印机通信。但对于退出,主线程直接与通知程序和打印机通信

这意味着可以在通知程序向打印机队列发送之前将退出消息添加到打印机队列。因此,考虑到这些操作:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <functional>
#include <any>
#include <condition_variable>

std::vector<std::function<void(std::any)>> functions;

enum FunctionCodes {
    EXIT = -1, NOTIFY = 0, PRINT
};

class Message
{
public:
    int code;
    std::any data;
};

void perform_function(const Message& message) {
    return functions[message.code](message.data);
}

namespace X {

    class MessageQueue
    {
        friend class Thread;

        class Node
        {
        public:
            Node(MessageQueue::Node *next, MessageQueue::Node *prev, const Message& message)
                : next(next), prev(prev), message(message) {}

        private:
            Node* next;
            Node* prev;
            Message message;
            friend class MessageQueue;
        };

        Node *head, *tail;
        std::mutex mutex;
        std::condition_variable cv;

    public:

        MessageQueue(Node *head, Node *tail) : head(head), tail(tail) {}
        MessageQueue() : MessageQueue(nullptr, nullptr) {}

        void push(const Message& message)
        {
            {
                std::lock_guard<std::mutex> lock(mutex);
                auto new_node = new Node(tail, nullptr, message);
                if (!tail) {
                    tail = head = new_node;
                } else {
                    tail->prev = new_node;
                    tail = new_node;
                }
            }
            cv.notify_one();
        }

        Message pop()
        {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, [this](){ return (bool)head; });
            auto head_to_delete = head;
            auto message = head->message;
            if (head->prev) {
                head->prev->next = nullptr;
            }
            head = head->prev;
            if (!head) {
                tail = nullptr;
            }
            delete head_to_delete;
            return message;
        }
    };

    class Thread
    {
        std::thread thread;
    public:
        MessageQueue queue;
        Thread() : queue(nullptr, nullptr),
            thread([this]() {
                while (true) {
                    auto message = queue.pop();
                    if (message.code == EXIT) {
                        break;
                    }
                    perform_function(message);
                }
            }) {}
        void join() { thread.join(); }
        ~Thread() { if (thread.joinable()) thread.join(); }
    };
}

X::Thread printer;
X::Thread notifier;

void cout(const std::string& text) {
    static std::mutex cout_mutex;
    std::lock_guard<std::mutex> guard(cout_mutex);
    std::cout << text << '\n';
}

void push_notify(std::any data) {
    notifier.queue.push({NOTIFY, std::move(data)} );
}

void notify(std::any data) {
    printer.queue.push({PRINT, std::move(data)});
}

void print(std::any data) {
    cout(std::any_cast<std::string>(std::move(data)));
}

void init_functions() {
    functions.resize(2);
    functions[NOTIFY] = notify;
    functions[PRINT] = print;
}

void exit_threads() {
    printer.queue.push({EXIT, {}});
    notifier.queue.push({EXIT, {}});
}

void join_threads() {
    printer.join();
    notifier.join();
}

int main()
{
    init_functions();

    int n;
    std::cin >> n;

    while (n--) {
        // FIXME why doesn't it print correctly?..
        std::string text;
        std::cin >> text;
        std::any data = std::move(text);
        push_notify(std::move(data));
    }

    exit_threads();
    join_threads();
}
打印机队列看起来像
a、b、EXIT、c
。它在打印
c
之前退出。如果在一行中输入所有输入,情况会更糟,因为主线程能够在通知程序向打印机发送任何内容之前将出口发送到打印机

解决方案是让
exit_threads
函数只向通知程序发送消息。当通知程序看到退出消息时,应将其转发到打印机并中断。确保发送到通知程序的所有消息在退出之前发送到打印机:

main sends 'a' to notifier
main sends 'b' to notifier
main sends 'c' to notifier
notifier sends 'a' to printer
notifier sends 'b' to printer
main sends EXIT to notifier
main sends EXIT to printer
notifier sends 'c' to printer
快速修复:

main sends 'a' to notifier
main sends 'b' to notifier
main sends 'c' to notifier
notifier sends 'a' to printer
notifier sends 'b' to printer
main sends EXIT to notifier
notifier sends 'c' to printer
notifier sends EXIT to printer
快速修复:

main sends 'a' to notifier
main sends 'b' to notifier
main sends 'c' to notifier
notifier sends 'a' to printer
notifier sends 'b' to printer
main sends EXIT to notifier
notifier sends 'c' to printer
notifier sends EXIT to printer