Locks are mandatory when you're updating data that does not fit into a single atomic type. You cannot use N atomics to create atomic update of a data structure that must be semantically atomic across its N members.
But consider: the generation counter effectively acts as a lock that locks out reader threads while the update takes place. It also serves to lock out other writer threads.
So yes, one can call that "lock-free" if one really wants to, but I find it more honest to just admit that it's a custom lock with custom properties.
Edit: with double buffering I guess it would be lock free, but still not wait free as a fast producer can still starve consumers indefinitely.
/Pedantic
With double buffering the reader can always fall back on the other buffer (hence it is lock-free, assuming somehow that writers always agree on the current write buffer), but then a fast writer can always prevent a slow reader from reading a consistent timestamp in a row which means it is not wait free.
Don't use spin locks unless you have profiled and have a clear understanding of the contention factors involved. Also be sure to test on single core and massively multicore.
Also look at whether you can use atomics. Atomics are better than lock guarded things in almost every way. The only time locks beat atomics is when you are updating a bunch of things in which case it may be faster to lock once than to update 10 atomic variables.
Message passing can also win sometimes over concurrent access even if it involves more copying. Profile and think.