I tried to implement a multithreading cache in C 11. I tried to create threads in the main function and passed the putcache function and getcache function as parameter. And I passed class object c1 to the two functions as parameters. However, I found that the complier gave me a error like this: In template: no matching constructor for initialization of '_Gp' (aka 'tuple<unique_ptr<std::__thread_struct>, void (*)(LRUCache), LRUCache>')
Here is my code:
#include <iostream>
#include <unordered_map>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std;
class LRUCache {
public:
class Node {
public:
int key,val;
Node* left,*right;
Node(int _key,int _val):key(_key),val(_val),left(NULL),right(NULL) {}
}*L,*R;
unordered_map<int,Node*> m;
int n;
mutex mtx;
condition_variable cv;
void insert(Node* node)
{
Node* next=L->right;
L->right=node;
node->right=next;
node->left=L;
next->left=node;
}
void erase(Node* node) {
node->left->right=node->right;
node->right->left=node->left;
}
LRUCache(int capacity) {
n=capacity;
L=new Node(-1,-1),R=new Node(-1,-1);
L->right=R;
R->left=L;
}
int get(int key) {
if(m.count(key)==0) return -1;
mtx.lock();
Node* node=m[key];
erase(node);
insert(node);
return node->val;
mtx.unlock();
}
void put(int key, int value) {
mtx.lock();
if(m.count(key)) {
m[key]->val=value;
erase(m[key]);
insert(m[key]);
} else {
Node* node=new Node(key,value);
if(m.size()==n) {
Node* tmp=R->left;
erase(tmp);
m.erase(tmp->key);
}
insert(node);
m[key]=node;
}
mtx.unlock();
}
};
void putcache(LRUCache c) {
for(int i=1;i<=10;i ) {
c.put(i,i 10);
this_thread::sleep_for(std::chrono::seconds(1));
}
}
void getcache(LRUCache c) {
for(int i=1;i<=10;i ) {
c.get(i);
this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
LRUCache c1(100);
std::thread t1(putcache,c1);
std::thread t2(getcache,c1);
}
CodePudding user response:
As @Nelfeal said:
LRUCache
contains two non-copyable members (mutex and condition variable) so its copy constructor is deleted.
You could not copy LRUCache
, by passing the c1
to the thread, you're copying it. Take a reference instead:
void putcache(LRUCache& c);
void getcache(LRUCache& c);
LRUCache c1(100);
std::thread t1(putcache, std::ref(c1));
std::thread t2(getcache, std::ref(c1));
And I think making the thread a class member would better fit your needs:
class LRUCache
{
void getcache();
void putcache();
}
LRUCache c1(100);
std::thread t1(&LRUCache::putcache, &c1);
std::thread t2(&LRUCache::getcache, &c1);
CodePudding user response:
std::thread
makes a copy of its parameters to ensure they live long enough for the new thread to start up. Also your putcache
and getcache
functions accept their parameters by value. Your LRUCache
class doesn't have a valid copy constructor though, so neither of those things can work.
If you want to pass a reference to c1
to both threads, then you'll need to wrap the parameters in a std::reference_wrapper
and make your putcache
and getcache
functions accept their parameters by value:
void putcache(LRUCache& c) { // <-------- NOTE: added &
for(int i=1;i<=10;i ) {
c.put(i,i 10);
this_thread::sleep_for(std::chrono::seconds(1));
}
}
void getcache(LRUCache& c) { // <-------- NOTE: added &
for(int i=1;i<=10;i ) {
c.get(i);
this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
LRUCache c1(100);
std::thread t1(putcache, std::ref(c1)); // <-------- NOTE: added std::ref
std::thread t2(getcache, std::ref(c1)); // <-------- NOTE: added std::ref
t1.join();
t2.join();
}
Keep in mind that it's up to you to ensure that c1
stays alive for the entire duration of your two threads. In this case, I've join
ed the two threads in main
to ensure it doesn't end before they're finished.