2016-06-20 7 views
4

私のゴーコードには競合状態があります。しかし、私は正しく同期していると確信しているので、私はそれを見つけることができません。数時間のデバッグの後、おそらく私はそれを見つけるのを助けることができます。Golang:関数タイプが異常な動作

package main 

import (
    "log" 
    "time" 
) 

type Parser struct { 
    callback Callback 
    callbackSet chan bool 
    test  int 
} 

func NewParser() Parser { 
    p := Parser{} 
    p.test = 100 
    p.callbackSet = make(chan bool) 
    return p 
} 

func (p *Parser) SetCallback(newCallback Callback) { 
    log.Println("=> SET CALLBACK: ", newCallback) 
    p.test = 100 
    p.callback = newCallback 
    log.Println("=> SETTING CALLBACK DONE") 
    p.callbackSet <- true 
} 

func (p *Parser) StartParsing() { 
    go p.parse() 
} 



func (p *Parser) parse() { 
    cb := <-p.callbackSet 
    _ = cb 
    log.Println("Verify Callback: ", p.callback) 
    log.Println("Verify Test Variable: ", p.test) 

    funcDone := make(chan bool) 
    go func() { 
     time.Sleep(3 * time.Second) // Some io-Operation here 
     funcDone <- true 
    }() 

    _ = <-funcDone 
} 

type Callback func(Message) 
type Message int 

type Dialog struct { 
    Parser Parser 
} 
func CreateDialog() (Dialog, error) { 
    d := Dialog{} 
    d.Parser = NewParser() 
    d.Parser.StartParsing() 
    return d, nil 
} 

func (d *Dialog) OnMessage(callback Callback) { 
    log.Println("dialog.OnMessage: ", callback) 
    time.Sleep(3 * time.Second) // This sleep is just to prove the synchronization. It could be removed. 
    d.Parser.SetCallback(callback) 
} 

func main() { 

    dialog, _ := CreateDialog() 
    dialog.OnMessage(func(m Message){ 
     log.Println("Message: ", m) 
    }) 

    time.Sleep(5 * time.Second) // Not clean but just to await all of the output 
} 

大きな問題は今:これら二つは全く同じに設定されているが、なぜp.callback<nil>p.test一方p.parseであるが、ではありません

まず第一に、ここで私の(非常に単純化された)コードです時間?

また、チャンネルp.callbackSetを使用して同期する必要がありますか? https://play.golang.org/p/14vn5Tie5Y

完全に実行可能な例では、私は単純な一つによって主な機能を交換しようとしました。私はバグがDialog構造体のどこかにあると思われます。その使用方法を回避すると、問題を再現できません。

func main() { 
    p := NewParser() 
    p.StartParsing() 
    p.SetCallback(func (m Message) { 
     log.Println("Message: ", m) 
    }) 

    time.Sleep(5 * time.Second) // Not clean but just to await all of the output 
} 

残りのコードは同じです。ここで変更(作業)バージョンの他の再生可能な例:あなたは値によってParserオブジェクトを格納し、CreateDialogからの値によってDialogを戻ってきているので、https://play.golang.org/p/0Y0nKbfcrv

+0

答えは(現在)間違っていますが、私は遊び場を見ました:問題は '' Set.callback() 'で' 'p.test'を変更しようとしたように、' 'p.callback'後でデフォルト値。 –

答えて

7

です。

CreateDialog内に作成された元のParserインスタンスは、Dialogインスタンスが値によって返されると失われます。

元のParserが解析され、ログに記録されたコールバックを受信します。したがって、次の3つのいずれかの操作を実行することができ、それを修正する

func CreateDialog() (Dialog, error) { 
    d := Dialog{} 
    d.Parser = NewParser() 
    d.Parser.StartParsing() // <-- this instance is parsing 
    return d, nil 
} 

func main() { 
    dialog, _ := CreateDialog() 
    // dialog.Parser <-- this is now a new instance which is NOT parsing 
    dialog.OnMessage(func(m Message){ 
     log.Println("Message: ", m) 
    }) 
} 

1)mainStartParsingを呼び出します。 CreateDialogからでポインタとして

func NewParser() *Parser { 
    p := &Parser{} 
    p.test = 100 
    p.callbackSet = make(chan bool) 
    return p 
} 

type Dialog struct { 
    Parser *Parser 
} 

3)戻りDialog

func main() { 
    dialog, _ := CreateDialog() 
    dialog.Parser.StartParsing(); 
    dialog.OnMessage(func(m Message){ 
     log.Println("Message: ", m) 
    }) 
} 

2)ダイアログでのポインタとしてストアParser

func CreateDialog() (*Dialog, error) { 
    d := &Dialog{} 
    d.Parser = NewParser() 
    d.Parser.StartParsing() 
    return d, nil 
} 

それを修正する必要があります。

+0

By "CreateDialog"内で作成された元の 'Parser'インスタンスは、' Dialog'インスタンスが値によって返されたときに失われます。 "ということは、ダイアログオブジェクトの' Parser'が新しいデフォルト値のParserオブジェクト? – Atmocreations

+0

ダイアログ内の '' Parser'とそのプロパティのすべてが値によってコピーされます。したがって、 'test'値100がコピーされ、' callback'の値がコピーされ、 'callbackSet'チャンネル(暗黙の参照型)がコピーされます。 'log.Println'文を' CreateDialog'と 'main'に置くことで、これを見ることができます。 – kbirk

+0

Aww ...ありがとう!今は魅力として働いています! – Atmocreations

関連する問題