提问人:shichao 提问时间:10/27/2023 最后编辑:Amitshichao 更新时间:10/30/2023 访问量:232
std::map 的元素如何从映射中删除自身?
How an element of std::map can delete itself from the map?
问:
我在不同的源文件中有两个类,class in 和 , class in 和 ,是一个类,它创建对象,并将其存储在映射中,当创建对象时,它会创建一个线程,我希望 s 对象从该映射中删除自己,当线程退出时,它是 的成员,但我的程序抛出异常。A
a.hpp
a.cpp
B
b.hpp
b.cpp
A
Singleton
B
B
B
A
// main.cpp
#include <iostream>
#include "a.hpp"
int main() {
A::get_instance().add(1);
int pause = 0; std::cin >> pause;
return 0;
}
// a.hpp
#ifndef __A_HPP__
#define __A_HPP__
#include <unordered_map>
#include <memory>
#include "b.hpp"
class A {
public:
void add(int i);
void remove(int i);
static A& get_instance();
private:
std::unordered_map<int, std::shared_ptr<B>> map_b_;
};
#endif
// a.cpp
#include "a.hpp"
void A::add(int i) {
std::cout << "add: " << i << std::endl;
map_b_[i] = std::move(std::make_shared<B>(i));
std::this_thread::sleep_for(3s);
}
void A::remove(int i) {
std::cout << "remove: " << i << std::endl;
if (map_b_.count(i)) {
map_b_.erase(i);
}
}
A& A::get_instance() {
static A instance;
return instance;
}
// b.hpp
#ifndef __B_HPP__
#define __B_HPP__
#include <thread>
#include <chrono>
#include <atomic>
#include <iostream>
using namespace std::chrono_literals;
class B {
public:
B(int id);
~B();
void stop();
void run();
private:
std::atomic<bool> run_flag_;
std::thread thr_;
int id_;
};
#endif
b.cpp
#include "b.hpp"
#include "a.hpp"
B::B(int id) {
id_ = id;
run_flag_ = true;
std::thread t(&B::run, this);
thr_ = std::move(t);
}
B::~B() {
std::cout << "~B(): " << id_ << std::endl;
stop();
}
void B::stop() {
run_flag_ = false;
if (thr_.joinable()) {
thr_.join();
}
}
void B::run() {
int count = 0;
while (count < 3 && run_flag_) {
std::cout << "processing id: " << id_ << std::endl;
std::this_thread::sleep_for(1s);
count ++;
}
A::get_instance().remove(id_);
}
# CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (demo)
SET(CMAKE_BUILD_TYPE "Debug")
# 指定生成目标
add_executable(
${PROJECT_NAME}
main.cpp
a.cpp
b.cpp
)
find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME} Threads::Threads)
我已经在我的 Linux docker 中运行了代码,但它抛出了一个错误,就像这样,我想知道我该怎么做才能从容器中删除一个本身。
root@53d8817a43a8:~/test-cpp/build# ./demo
add: 1
processing id: 1
processing id: 1
processing id: 1
remove: 1
~B(): 1
terminate called after throwing an instance of 'std::system_error'
what(): Resource deadlock avoided
Aborted
答:
对于您的要求,我会选择该设计:
实现 Publish Subscribe 设计模式(源代码)。该类继承自该类。该类继承自该类。Singleton
Subscriber
B
Publisher
该类具有 和 私有数据成员。increments 和 assigns 的构造函数。即每个对象都有一个唯一的 ID。因此,() 中的每个对象都有一个唯一的 id。 防止复制 B 对象很重要!B
inline static std::atomic_uint64_t unique_{ 0 }
uint64_t id_{ 0 }
B
++unique_
id_ = unique_
B
B
map_
std::unordered_map
- 在添加:创建一个对象时:,获取其 id,将其指针添加到 ,,最后:调用以运行其线程。
B
b
map_
subscribe(b)
b
该类有一个成员函数。由对象分离的线程获取对象成员函数的地址作为参数。当线程即将返回时,它会调用 .重要的是,只要一个对象的线程在运行,就不要从地图上删除/销毁它!B
void Done()
B
B
Done()
callback
callback
调用的实现:函数(类)。B::Done()
notify(id_)
Publisher
由于该类是 a,因此它的实例在 B
对象线程的上下文中截获此调用。Singleton
Subscriber
void update(Publisher* who, void* what = 0)
函数(覆盖 )将 转换为 (获取 id) 并从其 .Singleton::update
Subscriber
void* what
uint64_t
B
map_
- 删除时:在对象中查找:,按其 ID 查找,将其从 .
map_
B
b
unsubscribe(b)
map_
Add object 和 Remove object 的操作位于 2 个不同线程的上下文中,因此应使用 .也就是说,该类应该有一个( - M&M规则)。B
B
std::lock_gaurd lk(mutex_)
Singleton
mutable std::mutex mutex_
mutable
评论
weak_ptr
shared_ptr
weak_ptr
A::add
weak_ptr
A::remove
remove
join
detach
join
detach