Memory tools keep track of the state of the memory. Computes happens-before to find the data races. (2 accesses without happens-before accessing same memory location, one of them being a write).
Tool for memory debugging, memory leak detection, profiling
For every byte of memory location:
Detect and report incorrect memory access:
Detect data race and race conditions
pthread
API by intercepting POSIX functions.Examples:
Replaces your library calls with code that
Data races: Undefined behaviour due to concurrent memory access by at least two threads, at least one of which is a write, of the same memory location.
Broken invariants:
Lifetime issues:
join()
Eliminate the concurrency
Run on a single core
How many threads can my program run for optimal performance?
Processor architectures: x86 runs on TSO, so rel-acq may work better than expected lol
Library calls, operators may NOT be thread safe!
shared_ptr
Lock version:
template <typename T>
class shared_ptr {
private:
std::mutex* mut;
T* val;
int* rc;
public:
shared_ptr(T _val) : val(new T(_val)), rc(new int(1)), mut(new std::mutex) {}
shared_ptr(const shared_ptr<T>& copy) :
mut(copy.mut), val(copy.val), rc(copy.rc)
{
std::lock_guard lock(*mut);
*rc += 1;
}
shared_ptr& operator=(const shared_ptr<T>& copy) {
std::lock_guard lock(*copy.mut);
mut = copy.mut;
val = copy.val;
rc = copy.rc;
*rc += 1;
return this;
}
~shared_ptr() {
std::lock_guard lock(*mut);
*rc -= 1;
if (*rc == 0) {
delete val;
delete rc;
delete mut;
std::cerr << "terminated!" << std::endl;
}
}
T* get() { return val; }
void set(T _val) {
std::lock_guard lock(*mut);
*val = _val;
}
const T* get() const { return val; }
/*
int use_count() {
return rc->load();
}
*/
};
Atomic rc version:
template <typename T>
class shared_ptr {
private:
T* val;
std::atomic<int>* rc = nullptr;
public:
shared_ptr(T _val) : rc(new std::atomic<int>), val (new T(_val)) {}
shared_ptr(const shared_ptr<T>& copy) :
val(copy.val), rc(copy.rc) {
rc->fetch_add(1);
}
shared_ptr& operator=(const shared_ptr<T>& copy) {
val = copy.val;
rc = copy.rc;
rc->fetch_add(1);
return this;
}
~shared_ptr() {
if (rc->fetch_sub(1) == 0) {
delete val;
delete rc;
std::cerr << "terminated!" << std::endl;
}
}
T* get() { return val; }
const T* get() const { return val; }
};