Skip to content

Not thread safety? #31

@latifrons

Description

@latifrons

When poolInstance is shared in multiple go routines, object may be reused before cleaned, cleaned before reused or so.

package tests

import (
	"fmt"
	"sync"
	"testing"
	"time"

	"github.com/AlexsanderHamir/GenPool/pool"
)

type Data struct {
	Stage string
	pool.Fields[Data]
}

var poolInstance *pool.ShardedPool[Data, *Data]

func SetupPool() {
	var err error
	// PersistOrderUpdate
	{
		allocator := func() *Data {
			return &Data{
				Stage: "new",
			}
		}
		cleanupPolicy := pool.CleanupPolicy{
			Enabled:       true,
			Interval:      1 * time.Minute,
			MinUsageCount: 20,
		}
		cleaner := func(obj *Data) {
			if obj != nil {
				if obj.Stage != "used" {
					panic("cleaner received an obj.Stage != used: " + obj.Stage)
				}
				obj.Stage = "reset"
			} else {
				panic("cleaner received a nil obj")
			}
		}
		config := pool.Config[Data, *Data]{
			Cleanup:   cleanupPolicy,
			Allocator: allocator,
			Cleaner:   cleaner,
		}
		poolInstance, err = pool.NewPoolWithConfig(config)
		if err != nil {
			return
		}
	}
}

func TestThreadSafety(t *testing.T) {
	SetupPool()

	v := make(chan *Data, 100)
	// pool consumer
	go func() {
		for {
			obj := poolInstance.Get()
			if obj.Stage != "new" && obj.Stage != "reset" {
				// got a used obj that should be cleared before
				fmt.Println("got an obj.Stage != new && obj.Stage != reset: " + obj.Stage)
				//panic("got an obj.Stage != new && obj.Stage != reset: " + obj.Stage)
			}
			obj.Stage = "used"
			v <- obj
		}
	}()

	// put it back
	go func() {
		for {
			obj := <-v
			if obj.Stage != "used" {
				fmt.Println("returning an obj.Stage != used: " + obj.Stage)
				//panic("returning an obj.Stage != used: " + obj.Stage)
			}
			poolInstance.Put(obj)
		}
	}()

	select {}
}

func TestThreadSafety2(t *testing.T) {
	SetupPool()

	v := make(chan *Data, 100)

	mu := sync.Mutex{}
	// pool consumer
	go func() {
		for {
			mu.Lock()
			obj := poolInstance.Get()
			mu.Unlock()
			if obj.Stage != "new" && obj.Stage != "reset" {
				// got a used obj that should be cleared before
				fmt.Println("got an obj.Stage != new && obj.Stage != reset: " + obj.Stage)
				//panic("got an obj.Stage != new && obj.Stage != reset: " + obj.Stage)
			}
			obj.Stage = "used"
			v <- obj
		}
	}()

	// put it back
	go func() {
		for {
			obj := <-v
			if obj.Stage != "used" {
				fmt.Println("returning an obj.Stage != used: " + obj.Stage)
				//panic("returning an obj.Stage != used: " + obj.Stage)
			}
			mu.Lock()
			poolInstance.Put(obj)
			mu.Unlock()
		}
	}()

	select {}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions