Hazard pointers solve the problem but they are API-intrusive. Notably, hazard pointers require thread-local state, as well as some global structure that contains the entire list of threads. That means you have to register/deregister threads when when they are created/destroyed.
So essentially your API needs to look like this:
mylib_perthread_t *perthread = mythread_perthread_new();
// Later:
mylib_lockfreestack_push(obj, perthread, val);
// When the thread shuts down:
mylib_perthread_free(perthread);
But this is API-intrusive: 1. each thread must call mylib_perthread_new()
2. the thread needs thread-local storage for "perthread"
3. the thread must call mylib_perthread_free() before exiting
C11 and C++11 have thread-local storage, which solves (2), but (1) and (3) are still API-intrusive. Having to explicitly initialize/uninitialize a library per-thread resource is very uncommon. Worse, it doesn't compose well.Until this problem has a convenient and idiomatic solution, it's hard to imagine hazard pointers being very useful in idiomatic C and C++ APIs.
Without hazard pointers, your only real options are:
1. use a fixed-size structure (specify up front its max size)
2. don't free any nodes until the structure itself is deleted
The first is what this article does. The second is what boost.lockfree does. But without hazard pointers, you also need to solve the ABA problem, which requires either DCAS (double compare-and-swap), or a fixed-size structure that you index by offset instead of by pointer.It just occurred to me that a flow-chart of all these options and variations could be interesting.