producer-consumer problem with message passing
package main | |
import ( | |
"errors" | |
"fmt" | |
"math/rand" | |
"time" | |
) | |
func init() { | |
rand.Seed(time.Now().UnixNano()) | |
} | |
type Result struct { | |
s string | |
err error | |
} | |
type Message struct { | |
input string | |
resultChan chan Result | |
} | |
type Queue struct { | |
q [32]string | |
i int | |
popChan chan Message | |
pushChan chan Message | |
} | |
func (q *Queue) Push(s string) error { | |
resultChan := make(chan Result) | |
q.pushChan <- Message{ | |
input: s, | |
resultChan: resultChan} | |
result := <-resultChan | |
return result.err | |
} | |
func (q *Queue) Pop() (string, error) { | |
resultChan := make(chan Result) | |
q.popChan <- Message{ | |
resultChan: resultChan} | |
result := <-resultChan | |
return result.s, result.err | |
} | |
func (q *Queue) Controller() { | |
q.popChan = make(chan Message) | |
q.pushChan = make(chan Message) | |
for { | |
select { | |
case message := <-q.pushChan: | |
err := q.push(message.input) | |
message.resultChan <- Result{err: err} | |
case message := <-q.popChan: | |
s, err := q.pop() | |
message.resultChan <- Result{ | |
s: s, | |
err: err} | |
} | |
} | |
} | |
func (q *Queue) push(s string) error { | |
if q.i == 31 { | |
return errors.New("Full") | |
} | |
q.i++ | |
q.q[q.i] = s | |
return nil | |
} | |
func (q *Queue) pop() (string, error) { | |
if q.i == 0 { | |
return "", errors.New("Full") | |
} | |
q.i-- | |
return q.q[q.i], nil | |
} | |
func (q *Queue) Len() int { | |
return q.i | |
} | |
func main() { | |
var queue = new(Queue) | |
go queue.Controller() | |
go consumer(queue) | |
producer(queue) | |
} | |
func consumer(queue *Queue) { | |
for { | |
l := queue.Len() | |
for i := 0; i < l; i++ { | |
s, err := queue.Pop() | |
fmt.Printf("read: %s, %v\n", s, err) | |
if err != nil { | |
time.Sleep(1 * time.Second) | |
break | |
} | |
} | |
} | |
} | |
func producer(queue *Queue) { | |
for { | |
l := queue.Len() | |
for i := l; i < 32; i++ { | |
s := randomString() | |
err := queue.Push(s) | |
fmt.Printf("wrote: %s, %v\n", s, err) | |
if err != nil { | |
time.Sleep(1 * time.Second) | |
break | |
} | |
} | |
} | |
} | |
func randomString() string { | |
w := make([]byte, 5) | |
rand.Read(w) | |
return fmt.Sprintf("%X", w) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment