* fix bug #317.
* add counter for current task. If it's bigger then zero, do not quit background thread
* Revert "fix issue #317 (#331)"
This reverts commit fc43876cc5.
This commit is contained in:
@@ -37,6 +37,7 @@ type (
|
|||||||
confirmChan chan lang.PlaceholderType
|
confirmChan chan lang.PlaceholderType
|
||||||
guarded bool
|
guarded bool
|
||||||
newTicker func(duration time.Duration) timex.Ticker
|
newTicker func(duration time.Duration) timex.Ticker
|
||||||
|
currTask int
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -103,7 +104,9 @@ func (pe *PeriodicalExecutor) addAndCheck(task interface{}) (interface{}, bool)
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if pe.container.AddTask(task) {
|
if pe.container.AddTask(task) {
|
||||||
return pe.container.RemoveAll(), true
|
vals := pe.container.RemoveAll()
|
||||||
|
pe.currTask++
|
||||||
|
return vals, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
@@ -122,6 +125,9 @@ func (pe *PeriodicalExecutor) backgroundFlush() {
|
|||||||
commanded = true
|
commanded = true
|
||||||
pe.enterExecution()
|
pe.enterExecution()
|
||||||
pe.confirmChan <- lang.Placeholder
|
pe.confirmChan <- lang.Placeholder
|
||||||
|
pe.lock.Lock()
|
||||||
|
pe.currTask--
|
||||||
|
pe.lock.Unlock()
|
||||||
pe.executeTasks(vals)
|
pe.executeTasks(vals)
|
||||||
last = timex.Now()
|
last = timex.Now()
|
||||||
case <-ticker.Chan():
|
case <-ticker.Chan():
|
||||||
@@ -130,34 +136,26 @@ func (pe *PeriodicalExecutor) backgroundFlush() {
|
|||||||
} else if pe.Flush() {
|
} else if pe.Flush() {
|
||||||
last = timex.Now()
|
last = timex.Now()
|
||||||
} else if timex.Since(last) > pe.interval*idleRound {
|
} else if timex.Since(last) > pe.interval*idleRound {
|
||||||
|
var exit bool = true
|
||||||
pe.lock.Lock()
|
pe.lock.Lock()
|
||||||
pe.guarded = false
|
if pe.currTask > 0 {
|
||||||
|
exit = false
|
||||||
|
} else {
|
||||||
|
pe.guarded = false
|
||||||
|
}
|
||||||
pe.lock.Unlock()
|
pe.lock.Unlock()
|
||||||
|
|
||||||
pe.cleanup()
|
if exit {
|
||||||
return
|
// flush again to avoid missing tasks
|
||||||
|
pe.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pe *PeriodicalExecutor) cleanup() {
|
|
||||||
// avoid deadlock in Add()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case vals := <-pe.commander:
|
|
||||||
pe.enterExecution()
|
|
||||||
pe.confirmChan <- lang.Placeholder
|
|
||||||
pe.executeTasks(vals)
|
|
||||||
default:
|
|
||||||
// flush again to avoid missing tasks
|
|
||||||
pe.Flush()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pe *PeriodicalExecutor) doneExecution() {
|
func (pe *PeriodicalExecutor) doneExecution() {
|
||||||
pe.waitGroup.Done()
|
pe.waitGroup.Done()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,25 +140,6 @@ func TestPeriodicalExecutor_WaitFast(t *testing.T) {
|
|||||||
assert.Equal(t, total, cnt)
|
assert.Equal(t, total, cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeriodicalExecutor_Deadlock(t *testing.T) {
|
|
||||||
ticker := timex.NewFakeTicker()
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
exec := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, nil))
|
|
||||||
exec.newTicker = func(d time.Duration) timex.Ticker {
|
|
||||||
return ticker
|
|
||||||
}
|
|
||||||
ticker.Tick()
|
|
||||||
exec.lock.Lock()
|
|
||||||
exec.backgroundFlush()
|
|
||||||
time.Sleep(20 * time.Millisecond)
|
|
||||||
ticker.Tick()
|
|
||||||
exec.commander <- 1
|
|
||||||
exec.lock.Unlock()
|
|
||||||
<-exec.confirmChan
|
|
||||||
exec.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// go test -benchtime 10s -bench .
|
// go test -benchtime 10s -bench .
|
||||||
func BenchmarkExecutor(b *testing.B) {
|
func BenchmarkExecutor(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
@@ -168,3 +149,11 @@ func BenchmarkExecutor(b *testing.B) {
|
|||||||
executor.Add(1)
|
executor.Add(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPeriodicalExecutor_Deadlock(t *testing.T) {
|
||||||
|
executer := NewBulkExecutor(func(tasks []interface{}) {
|
||||||
|
}, WithBulkTasks(1), WithBulkInterval(time.Millisecond))
|
||||||
|
for i := 0; i < 1e6; i++ {
|
||||||
|
executer.Add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user