node lock をする時点でもうlock free じゃないけど…

lock free linked list のtraverse の続き

node lock をどうするか?

node にlock をいれれば、traverse で捨て子問題とかは回避できる。でも list_encabezado package では 行かの用に埋め込むのが前提だ

type User struct {
    ID int
    Name string
    list_encabezado.ListHead
}

ListHead の中身は prev と next のpointer だけだ

type ListHead struct {
	prev *ListHead
	next *ListHead
}

ここにsync.RWMutext とかいれちゃえばかんたんだが、使いたくない人もいるかもしれないし、 毎node sync.RWMutext のnode が使いたくない人も取るのはいやだ。てことで

それぞれの利用者側で mutext を追加して

type User struct {
    ID int
    Name string
    sync.RWMutex
    list_encabezado.ListHead
}

ListHeadからUserのRWMutext を取得する関数を用意する

func UserMutex(head *ListHead) *sync.RWMutex {
    user := list_encabezado.ElementOf(&User{}, head)
    return &user.RWMutex
}

list_encabezado.ElementOf は以下のようなものだ

func ElementOf(l List, head *ListHead) unsafe.Pointer {
	if head == nil || l == nil {
		return nil
	}

	return unsafe.Pointer(uintptr(unsafe.Pointer(head)) - l.Offset())
}

で以下のようにつかっていく

  
    user.Next(list_encabezado.LockFn(UserMutex))
    user.Prev(list_encabezado.LockFn(UserMutex))
    user.Delete(list_encabezado.LockFn(UserMutex))
    

いちよnode ごとにlock しながらすすめるようにした。(ちなみにPrev, Next のときはRLock している)

たぶん終わり。