Go 优雅地终止读卡器进程的基于定时器的写入和执行例程
我有以下代码,其中包含:Go 优雅地终止读卡器进程的基于定时器的写入和执行例程,go,goroutine,Go,Goroutine,我有以下代码,其中包含: 基于代码的编写器 按常规阅读 用于编写器和读取器通信的数据通道 停止写入器和停止读取器通道,用于优雅地停止写入器和读取器 用于处理“Ctrl-C”用户输入的信号处理程序 代码: 但是,大多数情况下,它会随着以下输出正常停止 2016/07/19 16:03:13 Starting Application 2016/07/19 16:03:13 Start Timer 2016/07/19 16:03:14 [READER] No ID to print 2016/0
- 基于代码的编写器
- 按常规阅读
- 用于编写器和读取器通信的数据通道
- 停止写入器和停止读取器通道,用于优雅地停止写入器和读取器
- 用于处理“Ctrl-C”用户输入的信号处理程序
2016/07/19 16:03:13 Starting Application
2016/07/19 16:03:13 Start Timer
2016/07/19 16:03:14 [READER] No ID to print
2016/07/19 16:03:15 [WRITER] Item ID: 1
2016/07/19 16:03:15 [READER] No ID to print
2016/07/19 16:03:15 [READER] Item ID: 1
2016/07/19 16:03:16 [READER] No ID to print
^C2016/07/19 16:03:16 Signal received: interrupt
2016/07/19 16:03:16 Signal sent
2016/07/19 16:03:16 Closing User Interupt Register go routing
2016/07/19 16:03:17 [WRITER] Item ID: 2
2016/07/19 16:03:17 [READER] No ID to print
2016/07/19 16:03:17 [READER] Item ID: 2
2016/07/19 16:03:17 About to close(reader_stop)
2016/07/19 16:03:17 close(reader_stop) finished
2016/07/19 16:03:17 About to stop timer
2016/07/19 16:03:17 Timer stopped
2016/07/19 16:03:17 About to close(writer_stop)
2016/07/19 16:03:17 close(writer_stop) finished
2016/07/19 16:03:17 Exiting Application
那怎么了?我如何确保它将正常停止所有go例程并关闭频道?您的代码中发生的情况是,一旦发送信号,一切都将正常工作,直到
读取器
功能结束。也就是说,信号被发送到writer\u stop
(语句writer\u stop在我看来,您应该更改读写器结构。您不需要停止读写器,只需停止写写器即可
当前结构的问题是,可能存在将被写入而从不读取的项。这可能是您不希望将data_通道设置为缓冲通道的原因。但仍有一项可能无法读取已写入通道的项
写入程序只需要一个停止通道。如果该通道发出信号并关闭数据通道,写入程序将停止。读卡器没有选择,只有一个用于项:=范围数据通道
。如果数据通道关闭,读卡器将清空其中的现有项并自行停止
替换此项:
func reader(reader_stop, writer_stop chan struct{}, data_channel chan uint32) {
var flag = true
for flag {
select {
case <-reader_stop:
writer_stop <- struct{}{}
flag = false
case data, ok := <-data_channel:
if ok {
log.Println("[READER] Item ID: ", data)
}
default:
time.Sleep(1 * time.Second)
log.Println("[READER] No ID to print")
continue
}
}
log.Println("About to close(reader_stop)")
close(reader_stop)
log.Println("close(reader_stop) finished")
}
删除:
defer close(data_channel)
并将其添加到此处:
case <-writer_stop:
close(data_channel)
log.Println("About to stop timer")
ticker.Stop()
log.Println("Timer stopped")
flag = false
您将不会有log.Println(“[READER]没有要打印的ID”)
消息,否则它将产生相同的结果
注意:其他代码需要相应地调整…例如删除writer\u stop通道。谢谢。但是我不能更改数据通道以限制。对于第二个解决方案,您能解释更多吗?因为如果我将write函数移动到默认部分,它将不会在给定时间写入。或者我错了?@abhink:我不知道我不明白。这个错误说的是在一个封闭的频道上发送。它不是挂起的,是吗?@TehSphinX它是挂起的。当我第二次点击“Ctrl-C”时它会惊慌失措。@TehSphinX代码挂起。在用于停止程序的错误之前,您可以看到第二个^C
。这是因为信号通道已关闭。正确,因为读卡器是使用者,它依赖于写卡器。请确保写卡器从不阻塞并且已正常关闭。然后您应该能够管理读卡器r正确。它是否说它试图在哪一行写入封闭通道?你能添加该信息吗?OP使用标志来终止循环,所以他实际上需要它:)如果我用你的建议替换它,我将无法每2秒写入一次。@ain:哦,是的,我没有意识到。可以使用中断
完成@凤凰城:看到我刚才在答案中加的注释2了吗?但是我根本不懂你的注释2。读者每2秒钟阅读一次是什么意思。我需要作家每2秒钟给读者写信。Break可以与mark一起使用。但我更喜欢和国旗一起使用。反正也没关系。@TehSphinXdata\u通道
被写入,而不是从中读取@凤凰城:@TehSphinx的意思可能是,你可以在读卡器中调整范围循环,而不是写。所以writer仍然每3秒写一次,但现在读卡器可以在数据通道上循环。我仍然认为问题在于中断的处理方式。
data_channel := make(chan uint32, 1)
func user_interupt_register() (writer_stop, reader_stop chan struct{}) {
writer_stop = make(chan struct{}, 1)
// same as before
go func() {
sig := <-signal_channel
writer_stop <- struct{}{} // change to writer_stop
// same as before
}()
return writer_stop, reader_stop
}
func reader(data_channel chan uint32) {
for item := range data_channel {
log.Println("[READER] Item ID: ", item)
}
}
func main() {
log.Println("Starting Application")
data_channel := make(chan uint32)
// defer close(data_channel)
writer_stop, _ := user_interupt_register()
log.Println("Start Timer")
ticker := time.NewTicker(2 * time.Second)
readTicker := time.NewTicker(1 * time.Second)
go reader(data_channel)
go func() { // to print intermittent message
for _ = range readTicker.C {
data_channel <- 0 // some insignificant value
}
}()
var item_id uint32 = 1
for _ = range ticker.C {
select {
case <-writer_stop:
data_channel <- item_id
close(data_channel)
ticker.Stop()
readTicker.Stop()
return
default:
data_channel <- item_id
item_id++
}
}
close(writer_stop)
}
func reader(reader_stop, writer_stop chan struct{}, data_channel chan uint32) {
var flag = true
for flag {
select {
case <-reader_stop:
writer_stop <- struct{}{}
flag = false
case data, ok := <-data_channel:
if ok {
log.Println("[READER] Item ID: ", data)
}
default:
time.Sleep(1 * time.Second)
log.Println("[READER] No ID to print")
continue
}
}
log.Println("About to close(reader_stop)")
close(reader_stop)
log.Println("close(reader_stop) finished")
}
func reader(writer_stop chan struct{}, data_channel chan uint32) {
for item := range data_channel {
log.Println("[READER] Item ID: ", data)
}
}
defer close(data_channel)
case <-writer_stop:
close(data_channel)
log.Println("About to stop timer")
ticker.Stop()
log.Println("Timer stopped")
flag = false
package main
import (
"log"
"os"
"os/signal"
"syscall"
"time"
)
func user_interupt_register() (writer_stop chan struct{}) {
writer_stop = make(chan struct{}, 1)
signal_channel := make(chan os.Signal)
signal.Notify(signal_channel, syscall.SIGINT, syscall.SIGTERM)
go func() {
for sig := range signal_channel {
log.Println("Signal received: ", sig)
writer_stop <- struct{}{}
log.Println("Signal sent")
break
}
close(signal_channel)
log.Println("Closing User Interupt Register go routing")
}()
return
}
func writer(item_id *uint32, data_channel chan uint32, writer_stop chan struct{}) {
log.Println("Start Timer")
ticker := time.NewTicker(2 * time.Second)
var flag = true
for flag {
select {
case <-ticker.C:
log.Println("[WRITER] Item ID: ", *item_id)
data_channel <- *item_id
*item_id++
case <-writer_stop:
close(data_channel)
log.Println("About to stop timer")
ticker.Stop()
log.Println("Timer stopped")
flag = false
}
}
}
func main() {
log.Println("Starting Application")
data_channel := make(chan uint32)
writer_stop := user_interupt_register()
var item_id uint32
item_id = 1
go writer(&item_id, data_channel, writer_stop)
for data := range data_channel {
log.Println("[READER] Item ID: ", data)
}
log.Println("About to close(writer_stop)")
close(writer_stop)
log.Println("close(writer_stop) finished")
log.Println("Exiting Application")
}