Browse Source

更新版本号并移除无效标志说明

将CHANGELOG.md中的版本号从“未发布”更新为“0.9.0”,日期设为2025-04-23,并在README.md中删除了关于`lionv1 --console-mode`标志的描述,因为它不再适用。同时简化了`--auto-reload`标志的文档,去除了与Windows平台相关的限制说明。
SongZihuan 6 days ago
parent
commit
27cfad494c

+ 6 - 0
CHANGELOG.md

@@ -7,6 +7,12 @@
 
 **注意:本文档内容若与[GitHub Wiki](https://github.com/SongZihuan/BackendServerTemplate/wiki/%E5%8F%98%E6%9B%B4%E6%97%A5%E5%BF%97)冲突,则以后者为准**
 
+## [未发布]
+
+### 新增
+
+- 添加线程独占任务功能。
+
 ## [0.9.0] - 2025-04-23
 
 ### 修复

+ 3 - 1
src/mainfunc/lion/v1/main.go

@@ -56,7 +56,9 @@ func MainV1(cmd *cobra.Command, args []string, inputConfigFilePath string, outpu
 		return exitutils.InitFailedError("Server Controller", err.Error())
 	}
 
-	ser1, _, err := example1.NewServerExample1(nil)
+	ser1, _, err := example1.NewServerExample1(&example1.ServerExample1Option{
+		LockThread: true,
+	})
 	if err != nil {
 		return exitutils.InitFailedError("Server Example1", err.Error())
 	}

+ 23 - 5
src/server/controller/controller.go

@@ -10,6 +10,7 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/serverinterface"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/goutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/strconvutils"
 	"reflect"
 	"sync"
@@ -25,10 +26,12 @@ type Controller struct {
 	name         string
 	stopWaitTime time.Duration
 	wg           *sync.WaitGroup
+	lockThread   bool
 }
 
 type ControllerOption struct {
 	StopWaitTime time.Duration
+	LockThread   bool
 }
 
 func NewController(opt *ControllerOption) (*Controller, error) {
@@ -37,9 +40,10 @@ func NewController(opt *ControllerOption) (*Controller, error) {
 	if opt == nil {
 		opt = &ControllerOption{
 			StopWaitTime: 10 * time.Second,
+			LockThread:   false,
 		}
 	} else {
-		if opt.StopWaitTime == 0 {
+		if opt.StopWaitTime <= 0 {
 			opt.StopWaitTime = 10 * time.Second
 		}
 	}
@@ -51,12 +55,13 @@ func NewController(opt *ControllerOption) (*Controller, error) {
 		name:         serverinterface.ControllerName,
 		wg:           new(sync.WaitGroup),
 		stopWaitTime: opt.StopWaitTime,
+		lockThread:   opt.LockThread,
 	}
 
-	{
-		controller.server[controller.name] = controller
-		controller.context[controller.name] = ctx
-	}
+	controller.running.Store(false)
+
+	controller.server[controller.name] = controller
+	controller.context[controller.name] = ctx
 
 	return controller, nil
 }
@@ -123,6 +128,19 @@ func (s *Controller) Run() {
 		s.running.Store(false)
 	}()
 
+	if s.lockThread {
+		err := goutils.LockOSThread()
+		if err != nil {
+			s.ctx.RunError(err)
+			return
+		}
+	}
+	defer func() {
+		if s.lockThread {
+			_ = goutils.UnlockOSThread()
+		}
+	}()
+
 	s.wg = new(sync.WaitGroup)
 	s.wg.Add(1)
 	defer s.wg.Done()

+ 28 - 5
src/server/example1/server.go

@@ -10,21 +10,25 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/serverinterface"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/goutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/strconvutils"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
 type ServerExample1 struct {
-	running      bool
+	running      atomic.Bool
 	ctx          *servercontext.ServerContext
 	name         string
 	wg           *sync.WaitGroup
 	stopWaitTime time.Duration
+	lockThread   bool
 }
 
 type ServerExample1Option struct {
 	StopWaitTime time.Duration
+	LockThread   bool
 }
 
 func NewServerExample1(opt *ServerExample1Option) (*ServerExample1, *servercontext.ServerContext, error) {
@@ -33,6 +37,7 @@ func NewServerExample1(opt *ServerExample1Option) (*ServerExample1, *serverconte
 	if opt == nil {
 		opt = &ServerExample1Option{
 			StopWaitTime: 10 * time.Second,
+			LockThread:   false,
 		}
 	} else {
 		if opt.StopWaitTime == 0 {
@@ -42,11 +47,14 @@ func NewServerExample1(opt *ServerExample1Option) (*ServerExample1, *serverconte
 
 	server := &ServerExample1{
 		ctx:          ctx,
-		running:      false,
 		name:         "example1",
 		wg:           new(sync.WaitGroup),
 		stopWaitTime: opt.StopWaitTime,
+		lockThread:   opt.LockThread,
 	}
+
+	server.running.Store(false)
+
 	err := server.init()
 	if err != nil {
 		return nil, nil, err
@@ -68,9 +76,24 @@ func (s *ServerExample1) GetCtx() *servercontext.ServerContext {
 }
 
 func (s *ServerExample1) Run() {
-	s.running = true
+	if s.running.Swap(true) {
+		return
+	}
 	defer func() {
-		s.running = false
+		s.running.Store(false)
+	}()
+
+	if s.lockThread {
+		err := goutils.LockOSThread()
+		if err != nil {
+			s.ctx.RunError(err)
+			return
+		}
+	}
+	defer func() {
+		if s.lockThread {
+			_ = goutils.UnlockOSThread()
+		}
 	}()
 
 	s.wg = new(sync.WaitGroup)
@@ -115,7 +138,7 @@ func (s *ServerExample1) Stop() {
 }
 
 func (s *ServerExample1) IsRunning() bool {
-	return s.running
+	return s.running.Load()
 }
 
 func _test() {

+ 28 - 5
src/server/example2/server.go

@@ -10,21 +10,25 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/serverinterface"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/goutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/strconvutils"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
 type ServerExample2 struct {
-	running      bool
+	running      atomic.Bool
 	ctx          *servercontext.ServerContext
 	name         string
 	wg           *sync.WaitGroup
 	stopWaitTime time.Duration
+	lockThread   bool
 }
 
 type ServerExample2Option struct {
 	StopWaitTime time.Duration
+	LockThread   bool
 }
 
 func NewServerExample2(opt *ServerExample2Option) (*ServerExample2, *servercontext.ServerContext, error) {
@@ -33,6 +37,7 @@ func NewServerExample2(opt *ServerExample2Option) (*ServerExample2, *serverconte
 	if opt == nil {
 		opt = &ServerExample2Option{
 			StopWaitTime: 10 * time.Second,
+			LockThread:   false,
 		}
 	} else {
 		if opt.StopWaitTime == 0 {
@@ -42,11 +47,14 @@ func NewServerExample2(opt *ServerExample2Option) (*ServerExample2, *serverconte
 
 	server := &ServerExample2{
 		ctx:          ctx,
-		running:      false,
 		name:         "example2",
 		wg:           new(sync.WaitGroup),
 		stopWaitTime: opt.StopWaitTime,
+		lockThread:   opt.LockThread,
 	}
+
+	server.running.Store(false)
+
 	err := server.init()
 	if err != nil {
 		return nil, nil, err
@@ -68,9 +76,24 @@ func (s *ServerExample2) GetCtx() *servercontext.ServerContext {
 }
 
 func (s *ServerExample2) Run() {
-	s.running = true
+	if s.running.Swap(true) {
+		return
+	}
 	defer func() {
-		s.running = false
+		s.running.Store(false)
+	}()
+
+	if s.lockThread {
+		err := goutils.LockOSThread()
+		if err != nil {
+			s.ctx.RunError(err)
+			return
+		}
+	}
+	defer func() {
+		if s.lockThread {
+			_ = goutils.UnlockOSThread()
+		}
 	}()
 
 	s.wg = new(sync.WaitGroup)
@@ -111,7 +134,7 @@ func (s *ServerExample2) Stop() {
 }
 
 func (s *ServerExample2) IsRunning() bool {
-	return s.running
+	return s.running.Load()
 }
 
 func _test() {

+ 28 - 5
src/server/example3/server.go

@@ -8,21 +8,25 @@ import (
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/serverinterface"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/goutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/strconvutils"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
 type ServerExample3 struct {
-	running      bool
+	running      atomic.Bool
 	ctx          *servercontext.ServerContext
 	name         string
 	wg           *sync.WaitGroup
 	stopWaitTime time.Duration
+	lockThread   bool
 }
 
 type ServerExample3Option struct {
 	StopWaitTime time.Duration
+	LockThread   bool
 }
 
 func NewServerExample3(opt *ServerExample3Option) (*ServerExample3, *servercontext.ServerContext, error) {
@@ -31,6 +35,7 @@ func NewServerExample3(opt *ServerExample3Option) (*ServerExample3, *serverconte
 	if opt == nil {
 		opt = &ServerExample3Option{
 			StopWaitTime: 10 * time.Second,
+			LockThread:   false,
 		}
 	} else {
 		if opt.StopWaitTime == 0 {
@@ -40,11 +45,14 @@ func NewServerExample3(opt *ServerExample3Option) (*ServerExample3, *serverconte
 
 	server := &ServerExample3{
 		ctx:          ctx,
-		running:      false,
 		name:         "example3",
 		wg:           new(sync.WaitGroup),
 		stopWaitTime: opt.StopWaitTime,
+		lockThread:   opt.LockThread,
 	}
+
+	server.running.Store(false)
+
 	err := server.init()
 	if err != nil {
 		return nil, nil, err
@@ -66,9 +74,24 @@ func (s *ServerExample3) GetCtx() *servercontext.ServerContext {
 }
 
 func (s *ServerExample3) Run() {
-	s.running = true
+	if s.running.Swap(true) {
+		return
+	}
 	defer func() {
-		s.running = false
+		s.running.Store(false)
+	}()
+
+	if s.lockThread {
+		err := goutils.LockOSThread()
+		if err != nil {
+			s.ctx.RunError(err)
+			return
+		}
+	}
+	defer func() {
+		if s.lockThread {
+			_ = goutils.UnlockOSThread()
+		}
 	}()
 
 	s.wg = new(sync.WaitGroup)
@@ -109,7 +132,7 @@ func (s *ServerExample3) Stop() {
 }
 
 func (s *ServerExample3) IsRunning() bool {
-	return s.running
+	return s.running.Load()
 }
 
 func _test() {

+ 41 - 0
src/utils/goutils/go.go

@@ -0,0 +1,41 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package goutils
+
+import (
+	"fmt"
+	"runtime"
+)
+
+var DefaultMaxProcs = runtime.GOMAXPROCS(0)
+
+func LockOSThread() (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("lock thread failed: %v", err)
+		}
+	}()
+
+	runtime.GOMAXPROCS(runtime.GOMAXPROCS(0) + 1)
+	runtime.LockOSThread()
+	return nil
+}
+
+func UnlockOSThread() (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("unlock thread failed: %v", err)
+		}
+	}()
+
+	procs := runtime.GOMAXPROCS(0) - 1
+	if procs < DefaultMaxProcs {
+		procs = DefaultMaxProcs
+	}
+
+	runtime.GOMAXPROCS(procs)
+	runtime.UnlockOSThread()
+	return nil
+}