Skip to content

Commit b61d4ae

Browse files
committed
all: add lower limit to the number of threads
1 parent 151d837 commit b61d4ae

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

mkill.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ import (
1919
)
2020

2121
var (
22-
pid = os.Getpid()
23-
maxThread = int32(runtime.NumCPU()) + 2 // 2 meaning runtime sysmon thread + template thread
24-
interval = time.Second
25-
debug = false
22+
pid = os.Getpid()
23+
minThreads = int32(runtime.NumCPU()) + 2 // minimum number of threads required by the runtime
24+
maxThreads = int32(runtime.NumCPU()) + 2 // 2 meaning runtime sysmon thread + template thread
25+
interval = time.Second
26+
debug = false
2627
)
2728

2829
// NumM returns the number of running threads.
@@ -41,14 +42,15 @@ func NumM() int {
4142
}
4243

4344
// GOMAXTHREADS sets the maximum number of system threads that allowed in a Go program
44-
// and returns the previous setting. If n < 1, it does not change the current setting.
45-
// The default allowed number of threads of a program is runtime.NumCPU() + 2.
45+
// and returns the previous setting. If n is lower than minimum required number of threads,
46+
// it does not change the current setting.
47+
// The minimum allowed number of threads of a program is runtime.NumCPU() + 2.
4648
func GOMAXTHREADS(n int) int {
47-
if n < 1 {
48-
return int(atomic.LoadInt32(&maxThread))
49+
if n < int(minThreads) {
50+
return int(atomic.LoadInt32(&maxThreads))
4951
}
5052

51-
return int(atomic.SwapInt32(&maxThread, int32(n)))
53+
return int(atomic.SwapInt32(&maxThreads, int32(n)))
5254
}
5355

5456
// Wait waits until the number of threads meet the GOMAXTHREADS settings.
@@ -82,7 +84,7 @@ func checkwork() {
8284
func init() {
8385
checkwork()
8486
if debug {
85-
fmt.Printf("mkill: pid %v, maxThread %v, interval %v\n", pid, maxThread, interval)
87+
fmt.Printf("mkill: pid %v, maxThread %v, interval %v\n", pid, maxThreads, interval)
8688
}
8789

8890
wg := sync.WaitGroup{}
@@ -92,10 +94,10 @@ func init() {
9294
select {
9395
case <-t.C:
9496
n := NumM()
95-
nkill := int32(n) - atomic.LoadInt32(&maxThread)
97+
nkill := int32(n) - atomic.LoadInt32(&maxThreads)
9698
if nkill <= 0 {
9799
if debug {
98-
fmt.Printf("mkill: checked #threads total %v / max %v\n", n, maxThread)
100+
fmt.Printf("mkill: checked #threads total %v / max %v\n", n, maxThreads)
99101
}
100102
continue
101103
}

mkill_test.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package mkill_test
77
import (
88
"context"
99
"fmt"
10+
"runtime"
11+
"sync"
1012
"testing"
1113
"time"
1214

@@ -17,17 +19,29 @@ func TestMKill(t *testing.T) {
1719
mkill.GOMAXTHREADS(10)
1820

1921
// create a lot of threads by sleep gs
22+
wg := sync.WaitGroup{}
23+
wg.Add(100000)
2024
for i := 0; i < 100000; i++ {
2125
go func() {
22-
time.Sleep(time.Second * 10)
26+
time.Sleep(time.Second * 1)
27+
wg.Done()
2328
}()
2429
}
2530

26-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*100)
31+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
2732
defer cancel()
2833
ok := mkill.Wait(ctx)
2934
if !ok {
30-
t.Fatal("mkill failed in 100s")
35+
t.Fatal("mkill failed in 10s")
36+
}
37+
wg.Wait()
38+
}
39+
40+
func TestMinThreads(t *testing.T) {
41+
old := mkill.GOMAXTHREADS(0)
42+
n := runtime.NumCPU()
43+
if mkill.GOMAXTHREADS(n-1) != old {
44+
t.Fatalf("number of threads is less than required in the runtime")
3145
}
3246
}
3347

0 commit comments

Comments
 (0)