本篇文章我们用Go实现一个自定义事件注册并等待唤醒的机制,其中涉及到的链表操作可以参考上一篇文章。文章参考自:https://github.com/brewlin/net-protocol

1.自定义唤醒事件

type EventMask uint16

const (
EventIn EventMask = 0x01
EventPri EventMask = 0x02
EventOut EventMask = 0x04
EventErr EventMask = 0x08
EventHUp EventMask = 0x10
EventNVal EventMask = 0x20
)

2.等待对象

type Entry struct {
Context interface{}
Callback EntryCallback
mask EventMask
ilist.Entry
}

3.等待对象被唤醒后的回调

type EntryCallback interface {
Callback(e *Entry)
}

4.EntryCallback接口的实现

Callback向等待对象的channel发送值以唤醒channel上的等待协程。

type channelCallback struct{}

func (*channelCallback) Callback(e *Entry) {
ch := e.Context.(chan struct{})
select {
case ch <- struct{}{}:
default:
}
}

5.初始化等待对象

这里的channel将会用于阻塞未被唤醒时的协程。

func NewChannelEntry(c chan struct{}) (Entry, chan struct{}) {
if c == nil {
c = make(chan struct{}, 1)
} return Entry{Context: c, Callback: &channelCallback{}}, c
}

6.等待队列

type Queue struct {
list ilist.List
mu sync.RWMutex
}

7.事件注册和事件注销

// EventRegister 注册等待对象
func (q *Queue) EventRegister(e *Entry, mask EventMask) {
q.mu.Lock()
e.mask = mask
q.list.PushBack(e)
q.mu.Unlock()
} // EventUnregister 注销等待对象
func (q *Queue) EventUnregister(e *Entry) {
q.mu.Lock()
q.list.Remove(e)
q.mu.Unlock()
}

8.事件唤醒

根据事件类型,通过回调函数向channel发送值以唤醒等待队列中的所有相关等待对象。

func (q *Queue) Notify(mask EventMask) {
q.mu.RLock()
for it := q.list.Front(); it != nil; it = it.Next() {
e := it.(*Entry)
if mask&e.mask != 0 {
e.Callback.Callback(e)
}
}
q.mu.RUnlock()
}

9.其他方法

// Events 返回已注册的事件类型
func (q *Queue) Events() EventMask {
ret := EventMask(0) q.mu.RLock()
for it := q.list.Front(); it != nil; it = it.Next() {
e := it.(*Entry)
ret |= e.mask
}
q.mu.RUnlock() return ret
} // IsEmpty 等待队列是否为空
func (q *Queue) IsEmpty() bool {
q.mu.Lock()
defer q.mu.Unlock() return q.list.Front() == nil
}

10.使用示例

func main() {
var wq waiter.Queue waitEntry, notifyCh := waiter.NewChannelEntry(nil)
wq.EventRegister(&waitEntry, waiter.EventIn)
defer wq.EventUnregister(&waitEntry) go func() {
for {
time.Sleep(time.Second)
wq.Notify(waiter.EventIn)
}
}() for {
<-notifyCh
fmt.Println("waked")
}
}

最新文章

  1. Remote Desktop Connection Manager
  2. udev
  3. JavaScript的学习2
  4. [异常解决] ubuntu上安装虚拟机遇到的问题(vmware坑了,virtual-box简单安装,在virtual-box中安装精简版win7)
  5. mybatis 中#{}与${}的区别
  6. animation动画兼容所有手机
  7. 挂载光盘与rpm安装
  8. DigitalOcean上SSH Key的创建(附DigitalOcean邀请)
  9. Normalize.css的使用(重置表)
  10. C++ Primer : 第十一章 : 关联容器之关联容器的迭代器和操作
  11. ONIX 实例
  12. mongodbVUE基本操作(转)
  13. 5)Javascript设计模式:extends模式
  14. Dynamics CRM2016 WebApi查询之alternate key
  15. cmd的变量总结
  16. Confluence 6 配置草稿保存的时间
  17. HTTP客户端/服务端 POST/GET
  18. /var/run/utmp文件操作函数
  19. CentOS中自动加载802.1q模块
  20. spring学习之springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序

热门文章

  1. 使用 DirectSound 播放 WAV 文件
  2. 使用idea的maven项目使用mybatis时遇到的坑
  3. Postman操作指南
  4. knock:端口敲门服务
  5. 桌面应用(.exe)设置窗口默认最大化、全屏(electron)
  6. CF1303F 题解
  7. 1487. 保证文件名唯一 (Medium)
  8. UVM——callback机制应用示例
  9. Mysql 原生语句
  10. ASP.NET Core MVC中调用Json()时默认使用Newtonsoft.Json返回数据