2011-09-25 50 views
1

我一直试图在Go中创建一个简单的事件循环包装器。但是我被困住了,我该如何跟踪当前线程中的操作? 我想让CurrentTick运行一个函数,并且即使调用函数退出,也不会开始下一个滴答,直到CurrentTick运行的所有函数都退出。我想我可能会使用一个互斥体来监视线程的数量,但是我意识到如果我一直在检查反复会调整CPU。如果我用了时间。睡觉它会是潜伏的。你将如何解决这个问题?如何等待低延迟的线程去?

package eventloop 

import (
    "reflect" 
) 

type eventLoop *struct{ 
    functions []reflect.Value 
    addFunc chan<-/*3*/ reflect.Value 
    mutex chan/*1*/ bool 
    threads int 
} 

func NewEventLoop() eventLoop { 
    var funcs chan reflect.Value 
    loop := eventLoop{ 
     []Reflect.Value{}, 
     funcs = make(chan reflect.Value, 3), 
     make(chan bool, 1), 
     0, 
    } 
    go func(){ 
     for { 
      this.mutex <- 1 
      if threads == 0 { 
      } 
     } 
    } 
} 

func (this eventLoop) NextTick(f func()) { 
    this.addFunc <- reflect.ValueOf(f) 
} 

func (this eventLoop) CurrentTick(f func()) { 
    this.mutex <- 1 
    threads += 1 
    <-this.mutex 
    go func() { 
     f() 
     this.mutex <- 1 
     threads -= 1 
     <-this.mutex 
    }() 
} 
+0

我想我自己想到了这一点,但我会测试它,并确保它的工作第一,如果它生病发布它作为答案。 –

回答

2

如果我理解你的意图,我认为你是过于复杂的事情。我会做这样的:

package eventloop 

type EventLoop struct { 
    nextFunc chan func() 
    curFunc chan func() 
} 

func NewEventLoop() *EventLoop { 
    el := &EventLoop{ 
     // Adjust the capacities to taste 
     make(chan func(), 3), 
     make(chan func(), 3), 
    } 
    go eventLoop(el) 
    return el 
} 

func (el *EventLoop) NextTick(f func()) { 
    el.nextFunc <- f 
} 

func (el *EventLoop) CurrentTick(f func()) { 
    el.curFunc <- f 
} 

func (el *EventLoop) Quit() { 
    close(el.nextFunc) 
} 

func eventLoop(el *EventLoop) { 
    for { 
     f, ok := <-el.nextFunc 
     if !ok { 
      return 
     } 
     f() 

     drain: for { 
      select { 
      case f := <-el.curFunc: 
       f() 
      default: 
       break drain 
      } 
     } 
    } 
} 

根据您的使用,您可能需要在程序退出前添加一些同步,以确保在循环完成所有任务。

+0

只有当您不允许“CurrentTick”同步时才有效。我想要做的更复杂一点。 –

+2

你能解释一下吗?在我的代码中,一个通道发送代替CurrentTick。据我所知,我的代码以与你一样的方式执行函数,但是使用较少的机器。我承认我不明白NextTick应该在你的代码中做什么,因为它看起来像缺少了一部分。 –

+1

好的,我根据你的回答修改了我的代码。这更接近你想要的吗? –

1

我想出了自己,经过很多问题和随机问题,包括使用15作为长度而不是容量......似乎你只是有一个线程发送消息后,你减少计数器。 (loop.tick部分可以内联,但我并不担心)

package eventloop 

type eventLoop struct{ 
    functions []func() 
    addFunc chan/*3*/ func() 
    mutex chan/*1*/ bool 
    threads int 
    waitChannel chan bool 
    pauseState chan bool 
} 
func (this *eventLoop) NextTick (f func()) { 
    this.addFunc <- f 
} 

func (this *eventLoop) tick() { 
    this.mutex <- true 
    for this.threads != 0 { 
     <-this.mutex 
     <-this.waitChannel 
     this.mutex <- true 
    } 
    <-this.mutex 
    L1: for { 
     select { 
      case f := <-this.addFunc: 
       this.functions = append(this.functions,f) 
      default: break L1 
     } 
    } 
    if len(this.functions) != 0 { 
     this.functions[0]() 
     if len(this.functions) >= 2 { 
      this.functions = this.functions[1:] 
     } else { 
      this.functions = []func(){} 
     } 
    } else { 
     (<-this.addFunc)() 
    } 
} 
func (this *eventLoop) CurrentTick (f func()) { 
    this.mutex <- true 
    this.threads += 1 
    <-this.mutex 
    go func() { 
     f() 
     this.mutex <- true 
     this.threads -= 1 
     <-this.mutex 
     this.waitChannel <- true 
    }() 
} 
func NewEventLoop() *eventLoop { 
    funcs := make(chan func(),3) 
    loop := &eventLoop{ 
     make([]func(),0,15), /*functions*/ 
     funcs, /*addFunc*/ 
     make(chan bool, 1), /*mutex for threads*/ 
     0, /*Number of threads*/ 
     make(chan bool,0), /*The "wait" channel*/ 
     make(chan bool,1), 
    } 
    go func(){ 
     for { loop.tick() } 
    }() 
    return loop 
} 

注意:这仍然有很多其他问题。