?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();}}
};