Advertisement
Guest User

atomic-go

a guest
Jan 19th, 2015
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 4.77 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "fmt"
  5.     "math/rand"
  6.     "time"
  7.     "runtime"
  8.     "sync"
  9. )
  10.  
  11.  
  12. func init() {
  13.     runtime.GOMAXPROCS(runtime.NumCPU())
  14. }
  15.  
  16. // Data type required by task.
  17. type bucketList interface {
  18.     // Two operations required by task.  Updater parameter not specified
  19.     // by task, but useful for displaying update counts as an indication
  20.     // that transfer operations are happening "as often as possible."
  21.     bucketValue(bucket int) int
  22.     transfer(b1, b2, ammount, updater int)
  23.  
  24.     // Operation not specified by task, but needed for synchronization.
  25.     snapshot(bucketValues []int, transferCounts []int)
  26.  
  27.     // Operation not specified by task, but useful.
  28.     buckets() int // number of buckets
  29. }
  30.  
  31. // Total of all bucket values, declared as a const to demonstrate that
  32. // it doesn't change.
  33. const originalTotal = 1000
  34.  
  35. // Updater ids, used for maintaining transfer counts.
  36. const (
  37.     idOrder = iota
  38.     idChaos
  39.     nUpdaters
  40. )
  41.  
  42. func main() {
  43.     // Create a concrete object implementing the bucketList interface.
  44.     bl := newRwList(20, originalTotal, nUpdaters)
  45.  
  46.     // Three concurrent tasks.
  47.     go order(bl)
  48.     go chaos(bl)
  49.     buddha(bl)
  50. }
  51.  
  52. // The concurrent tasks exercise the data operations by going through
  53. // the bucketList interface.  They do no explicit synchronization and
  54. // are not responsible for maintaining invariants.
  55.  
  56. // Exercise (1.) required by task: make values more equal.
  57. func order(bl bucketList) {
  58.     r := rand.New(rand.NewSource(time.Now().UnixNano()))
  59.     nBuckets := bl.buckets()
  60.     for {
  61.         b1 := r.Intn(nBuckets)
  62.         b2 := r.Intn(nBuckets)
  63.         v1 := bl.bucketValue(b1)
  64.         v2 := bl.bucketValue(b2)
  65.         if v1 > v2 {
  66.             bl.transfer(b1, b2, (v1-v2)/2, idOrder)
  67.         } else {
  68.             bl.transfer(b2, b1, (v2-v1)/2, idOrder)
  69.         }
  70.     }
  71. }
  72.  
  73. // Exercise (2.) required by task: redistribute values.
  74. func chaos(bl bucketList) {
  75.     r := rand.New(rand.NewSource(time.Now().UnixNano()))
  76.     nBuckets := bl.buckets()
  77.     for {
  78.         b1 := r.Intn(nBuckets)
  79.         b2 := r.Intn(nBuckets)
  80.         bl.transfer(b1, b2, r.Intn(bl.bucketValue(b1)+1), idChaos)
  81.     }
  82. }
  83.  
  84. // Exercise (3.) requred by task: display total.
  85. func buddha(bl bucketList) {
  86.     nBuckets := bl.buckets()
  87.     s := make([]int, nBuckets)
  88.     tc := make([]int, nUpdaters)
  89.     var total, nTicks int
  90.  
  91.     fmt.Println("sum  ---updates---    mean  buckets")
  92.     tr := time.Tick(time.Second)
  93.     for {
  94.         var sum int
  95.         <-tr
  96.         bl.snapshot(s, tc)
  97.         for _, l := range s {
  98.             if l < 0 {
  99.                 panic("sob") // invariant not preserved
  100.             }
  101.             sum += l
  102.         }
  103.         // Output number of updates per tick and cummulative mean
  104.         // updates per tick to demonstrate "as often as possible"
  105.         // of task exercises 1 and 2.
  106.         total += tc[0] + tc[1]
  107.         nTicks++
  108.         fmt.Printf("%d %6d %6d %7d  %v\n", sum, tc[0], tc[1], total/nTicks, s)
  109.         if sum != originalTotal {
  110.             panic("weep") // invariant not preserved
  111.         }
  112.     }
  113. }
  114.  
  115. /////////////////////////////////////////////////////
  116.  
  117. // rwList, rw is for RWMutex-synchronized.
  118. type rwList struct {
  119.     b []int // bucket data specified by task
  120.  
  121.     // Syncronization objects.
  122.     m   []sync.Mutex // mutex for each bucket
  123.  
  124.     tc []int // a transfer count for each updater
  125. }
  126.  
  127. // Constructor.
  128. func newRwList(nBuckets, initialSum, nUpdaters int) *rwList {
  129.     bl := &rwList{
  130.         b:  make([]int, nBuckets),
  131.         m:  make([]sync.Mutex, nBuckets),
  132.         tc: make([]int, nUpdaters),
  133.     }
  134.     for i, dist := nBuckets, initialSum; i > 0; {
  135.         v := dist / i
  136.         i--
  137.         bl.b[i] = v
  138.         dist -= v
  139.     }
  140.     return bl
  141. }
  142.  
  143. // Four methods implementing the bucketList interface.
  144. func (bl *rwList) bucketValue(b int) int {
  145.     bl.m[b].Lock() // lock on bucket ensures read is atomic
  146.     r := bl.b[b]
  147.     bl.m[b].Unlock()
  148.     return r
  149. }
  150.  
  151. func (bl *rwList) transfer(b1, b2, a int, ux int) {
  152.     if b1 == b2 { // null operation
  153.         return
  154.     }
  155.     if b1 < b2 {
  156.         bl.m[b1].Lock()
  157.         bl.m[b2].Lock()
  158.     } else {
  159.         bl.m[b2].Lock()
  160.         bl.m[b1].Lock()
  161.     }
  162.     // clamp
  163.     if a > bl.b[b1] {
  164.         a = bl.b[b1]
  165.     }
  166.     // transfer
  167.     bl.b[b1] -= a
  168.     bl.b[b2] += a
  169.     bl.tc[ux]++ // increment transfer count
  170.     bl.m[b1].Unlock()
  171.     bl.m[b2].Unlock()
  172. }
  173.  
  174. func (bl *rwList) snapshot(s []int, tc []int) {
  175.     for i := range bl.m {
  176.         bl.m[i].Lock()
  177.     }
  178.     copy(s, bl.b)
  179.     copy(tc, bl.tc)
  180.     for i := range bl.tc {
  181.         bl.tc[i] = 0
  182.     }
  183.     for i := range bl.m {
  184.         bl.m[i].Unlock()
  185.     }
  186. }
  187.  
  188. func (bl *rwList) buckets() int {
  189.     return len(bl.b)
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement