2011-09-25 8 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 
} 

注:これにはまだ多くの問題があります。

関連する問題