My program here, tries to make a tread safe stack by using locks.
This was quite simple.. but I want to know if I'm making a conceptual mistake.
(Is using different mutex (s) for two data members which may not be accessed in the same function, a good idea?)
The test program spawns 6 threads pushing a number into the same stack, 500 times each.
And after joining them I check that the stack's size is 3000.
(Without the locking the number is about ~200 less !!..that gives me some confidence about the correctness of the code.)
Test code:
Code:
#include<thread>
#include<mutex>
#include<iostream>
#include<array>
#include<exception>
#include<functional>
#include<vector>
int main()
{
mm::stack<int,10000> si;
auto foo = [](mm::stack<int,10000>& si,int n){for(int i=0;i<500;i++)si.push(n);};
//^ Pushes n 500 times into the stack si.
std::vector<std::thread> threads;
for(int i=0;i<6;i++)
threads.push_back(std::thread(foo,std::ref(si),i));
for(auto&x:threads)x.join();
si.debug_print();
}
The stack:
Code:
namespace mm
{
template<typename T, std::size_t MAX=10>
class stack
{
typedef std::lock_guard<std::mutex> lgm;
public:
stack():head(-1){};
bool empty()
{
lgm l(head_lock);
return (head==-1);
}
T top()
{
if(empty())throw(std::runtime_error("Empty"));
lgm d(data_lock),h(head_lock);
return data[head];
}
std::size_t size()
{
lgm l(head_lock);
return head+1;
}
void push(const T& t)
{
if(size()==MAX)throw(std::runtime_error("Overflow"));
lgm d(data_lock),h(head_lock);
data[++head]=t;
}
void pop()
{
if(empty())throw(std::runtime_error("Underflow"));
lgm h(head_lock);
--head;
}
void debug_print()
{
for(int i=0;i<=head;i++)
std::cout<<data[i];
std::cout<<"\nSize: "<<head+1;
}
private:
std::array<T,MAX> data;
int head;
std::mutex data_lock;
std::mutex head_lock;
};
}