A professional C++ implementation of the Eraser lockset algorithm for dynamic data race detection in multi-threaded programs. Detects potential race conditions by tracking lock acquisition patterns and shared variable access.
This project implements a dynamic data race detector that uses the lockset algorithm (Eraser algorithm) to detect potential data races in multi-threaded C++ programs. The detector monitors thread access patterns to shared variables and verifies that all accesses are properly protected by locks.
The Eraser algorithm works by:
- Maintaining a lockset for each thread (set of locks currently held)
- Tracking access patterns to shared variables
- Detecting when concurrent accesses occur without common locks
- Reporting potential data races
- Lockset Algorithm: Full implementation of the Eraser algorithm for data race detection
- Thread Tracking: Monitors thread access patterns and lock acquisitions
- State Management: Tracks shared variable states (Virgin, Exclusive, Shared, etc.)
- Race Detection: Identifies concurrent accesses without proper synchronization
- Statistics: Provides detailed statistics on accesses, locks, and detected races
- Error Handling: Comprehensive null pointer checks and error reporting
- Professional Code: Well-documented, clean, and maintainable codebase
Lockset_algorithm/
βββ include/ # Header files
β βββ Accesstype.h
β βββ DataRaceDetector.h
β βββ Lock.h
β βββ SharedVariable.h
β βββ Thread.h
βββ src/ # Source files
β βββ DataRaceDetector.cpp
β βββ Lock.cpp
β βββ main.cpp
β βββ SharedVariable.cpp
β βββ Thread.cpp
βββ examples/ # Example and test programs
β βββ barrier.cpp
β βββ benchmark.cpp
β βββ bigTest.cpp
β βββ giantTest.cpp
β βββ r_r_example.cpp
β βββ read_write_ex.cpp
β βββ w_w_example.cpp
βββ Makefile # Build configuration
βββ README.md # This file
βββ LICENSE # License file
- C++11 or later compiler (g++ or clang++)
- pthread library (usually included with the compiler)
- Make (optional, for using Makefile)
- Linux/Unix: pthread is typically included
- Windows (MinGW/MSYS2): pthread is available via MinGW-w64
- macOS: pthread is included in the system
# Build the main program
make
# Build all examples
make examples
# Clean build artifacts
make clean
# Build specific example
make barrier
make benchmarkNote: If make is not available on Windows, you can install it via:
- MinGW/MSYS2:
pacman -S make - Chocolatey:
choco install make - WSL: Use the Linux version
If make is not available, you can compile manually:
# Main program
g++ -std=c++11 -pthread -I./include src/main.cpp src/DataRaceDetector.cpp src/Lock.cpp src/Thread.cpp src/SharedVariable.cpp -o main
# Example: Build read_write_ex
g++ -std=c++11 -pthread -I./include examples/read_write_ex.cpp src/DataRaceDetector.cpp src/Lock.cpp src/Thread.cpp src/SharedVariable.cpp -o examples/read_write_ex#include "../include/DataRaceDetector.h"
#include "../include/Lock.h"
#include "../include/SharedVariable.h"
#include "../include/Thread.h"
#include "../include/Accesstype.h"
int main() {
// Create detector and resources
DataRaceDetector drd;
Lock lock1(1);
SharedVariable var1("var1");
drd.locksetMainStart();
// Register and use locks properly
Thread thread(1);
drd.registerThread(&thread);
drd.registerSharedVariable(&var1);
// Acquire lock before access
drd.onLockAcquire(&thread, &lock1, true, &var1);
drd.onSharedVariableAccess(&thread, &var1, AccessType::WRITE);
drd.onLockRelease(&thread, &lock1, &var1);
drd.locksetMainEnd();
// Print statistics
std::cout << "Data races detected: " << drd.getNumDataRaces() << std::endl;
return 0;
}./mainThe program demonstrates two scenarios:
- Correct usage: Proper lock usage preventing data races
- Incorrect usage: Missing locks leading to detected data races
The main detector class implementing the lockset algorithm. It:
- Tracks registered threads and shared variables
- Monitors lock acquisitions and releases
- Detects data races based on lockset intersections
- Provides statistics on detected races
Represents a thread and maintains:
- Lockset: Set of all locks currently held
- Write Lockset: Set of locks held in write mode
- Thread ID for identification
Represents a synchronization lock that:
- Tracks which thread currently holds it
- Associates with shared variables it protects
- Supports read/write mode tracking
Represents a shared variable with:
- State tracking: Virgin, Exclusive, Shared, SharedModified, etc.
- Access history: Which thread is currently accessing
- Candidate locks: Locks that protect this variable
Enumeration for access operations:
READ: Read access operationWRITE: Write access operation
Shared variables transition through states:
- Virgin: Never accessed
- Initializing: First write access
- Exclusive: Single thread has exclusive access
- Shared: Multiple threads reading
- SharedModified: Multiple threads with at least one write
- Clean: Reset state
The examples/ directory contains several demonstration programs:
- read_write_ex.cpp: Basic read/write access patterns
- r_r_example.cpp: Read-read scenarios
- w_w_example.cpp: Write-write scenarios
- barrier.cpp: Barrier synchronization examples
- benchmark.cpp: Performance benchmarking
- bigTest.cpp: Large-scale test scenarios
- giantTest.cpp: Extensive stress testing
To build and run an example:
make read_write_ex
./examples/read_write_exThe lockset algorithm detects data races by:
- Maintaining Locksets: Each thread maintains a set of locks it currently holds
- Tracking Accesses: When a thread accesses a shared variable, the detector checks:
- Is another thread currently accessing the same variable?
- Do both threads have at least one common lock?
- Race Detection: If concurrent access occurs without common locks, a data race is reported
The algorithm checks for common locks between threads using:
- Regular lockset intersection
- Write lockset intersection
- Cross-intersection (one thread's write lockset with another's regular lockset)
The detector provides the following statistics:
getNumAccesses(): Total number of variable accessesgetNumLockAcquisitions(): Total lock acquisitionsgetNumLockReleases(): Total lock releasesgetNumDataRaces(): Total data races detected
The implementation includes comprehensive error handling:
- Null pointer checks for all public methods
- Barrier initialization validation
- Lock ownership verification
- Error messages via
std::cerr
See LICENSE file for details.
This is a professional implementation suitable for:
- Educational purposes
- Research in concurrent programming
- Integration into larger projects
- Learning data race detection algorithms
- Eraser: A Dynamic Data Race Detector for Multithreaded Programs by Stefan Savage, Michael Burrows, Greg Nelson, Patrick Sobalvarro, and Thomas Anderson (1997)
The Eraser algorithm is a foundational technique in:
- Dynamic analysis tools
- Thread sanitizers
- Concurrent program verification
- Data race detection research
Note: This implementation is designed for educational and research purposes. For production use, consider established tools like ThreadSanitizer (TSan) or Helgrind. // Optimized for thread-safety and race condition detection