IT评测·应用市场-qidao123.com技术社区
标题:
C++手撕共享指针、多线程交替、LRU缓存
[打印本页]
作者:
伤心客
时间:
2025-3-26 06:46
标题:
C++手撕共享指针、多线程交替、LRU缓存
1.
共享指针
#include <atomic>
#include <iostream>
template <typename T> class sharedptr {
private:
T *ptr;
std::atomic<size_t> *count;
public:
sharedptr(T *p) : ptr(p), count(new std::atomic<size_t>(1)) {}
sharedptr(const sharedptr &other) : ptr(other.ptr), count(other.count) {
(*count)++;
}
sharedptr(sharedptr &&other) : ptr(other.ptr), count(other.count) {
other.ptr = nullptr;
other.count = nullptr;
}
// 拷贝赋值运算符
// 何时调用?当用一个 已存在的对象(左值)
// 赋值给另一个已存在的对象时: Myclass a,b;
sharedptr &operator=(const sharedptr &other) {
if (this != &other) {
release();
ptr = other.ptr;
count = other.count;
(*count)++;
}
return *this;
}
// 移动赋值运算符
sharedptr &operator=(sharedptr &&other) {
if (this != &other) {
ptr = other.ptr;
count = other.count;
other.ptr = nullptr;
other.count = nullptr;
}
return *this;
}
void release() {
if (count != nullptr && (--(*count)) == 0) {
delete ptr;
delete count;
}
}
~sharedptr() { release(); }
T *operator->() { return ptr; }
T &operator*() { return *ptr; }
};
int main() {}
复制代码
1. 快速影象
双成员布局
:
T* ptr管理资源
atomic<size_t>* count保证线程安全
五大特殊函数
:
// 1. 构造
explicit Shared_Ptr(T* p = nullptr)
// 2. 拷贝构造
Shared_Ptr(const Shared_Ptr&)
// 3. 移动构造(noexcept优化)
Shared_Ptr(Shared_Ptr&&) noexcept
// 4. 拷贝赋值(自检+释放旧值:等号左)
operator=(const Shared_Ptr&)
// 5. 移动赋值(自检+释放旧值:等号右)
operator=(Shared_Ptr&&) noexcept
复制代码
发起手写时按以下顺序实现
成员变量
构造函数
拷贝构造/赋值
移动构造/赋值
析构函数
操作符重载
辅助方法
2. 多线程交替打印
代码:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int m;
std::mutex mtx;
std::condition_variable cv;
void print(int target) {
for (int i = 0; i < 10; i++) {
// 这行代码相当重要
std::unique_lock<std::mutex> lock(mtx);
// 条件谓词不接受参数
cv.wait(lock, [&]() { return m == target; });
std::cout << m << std::endl;
m = (m + 1) % 3;
cv.notify_all();
}
}
int main() {
m = 0;
std::thread t1(print, 0);
std::thread t2(print, 1);
std::thread t3(print, 2);
t1.join();
t2.join();
t3.join();
}
复制代码
1. std::unique_lock<std::mutex>对象lock和std::mutex对象mtx是什么关系?
std::unique_lock<std::mutex> 是一个管理互斥量(std::mutex)的 RAII(资源获取即初始化)包装器。两者的关系如下:
绑定关系
:当你创建一个 std::unique_lock<std::mutex> 对象时,通常会将一个 std::mutex 对象(好比 mtx)传递给它。此时,unique_lock 会主动尝试锁定这个互斥量。
主动管理
:unique_lock 在其生命周期内拥有并管理这个 mtx 的锁定状态。当 unique_lock 对象烧毁时(例如超出作用域),它会主动解锁 mtx,制止手动解锁带来的错误风险。
灵活性
:与 std::lock_guard 相比,unique_lock 提供了更多的灵活性,好比能够延迟锁定、手动解锁或重新锁定,以及支持条件变量等候时的锁管理。
个人明白:所谓mutex(mutual exclusion),本身仅是声明了一个互斥量,此时并不包含锁的意义
2. 简述一下cv.wait和notify做了什么?
cv.wait
等候与解锁
:调用 cv.wait(lock, predicate) 时,线程会进入等候状态,同时主动释放传入的 std::unique_lock 持有的互斥量。这使得其他线程可以获得该互斥量,从而修改共享数据。
阻塞与恢复
:当等候的条件(通常由传入的 lambda 表达式 predicate 检查)不满意时,线程会不停阻塞。待其他线程调用 notify 方法后,等候线程会被叫醒并重新尝试获取锁,随后检查条件,直到条件满意为止。
notify
叫醒等候线程
:cv.notify_one() 会叫醒一个正等候此条件变量的线程,而 cv.notify_all() 则会叫醒所有等候的线程。
同步机制
:当某个线程修改了共享数据并满意了等候线程所盼望的条件后,它会调用 notify 方法通知等候线程,促使它们从阻塞状态中恢复,继续执行。
3. LRU缓存
class LRUCache {
private:
int capacity;
list<pair<int,int>> mylist;
unordered_map<int,list<pair<int,int>>::iterator> umap;
public:
LRUCache(int capacity):capacity(capacity) {
}
int get(int key) {
if(umap.find(key)==umap.end()) {return -1;}
int value=umap[key]->second;
mylist.erase(umap[key]);
mylist.push_front({key,value});
umap[key]=mylist.begin();
return value;
}
void put(int key, int value) {
if(umap.find(key)!=umap.end()){
mylist.erase(umap[key]);
mylist.push_front({key,value});
umap[key]=mylist.begin();
} else{
if(umap.size()==capacity){
// 不能直接删除end()
// umap.erase(mylist.end());
int old_key=mylist.back().first;
umap.erase(old_key);
mylist.pop_back();
}
mylist.push_front({key,value});
umap[key]=mylist.begin();
}
}
};
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4