init
This commit is contained in:
commit
659ae65a59
|
@ -0,0 +1,80 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type counterID uint32
|
||||
|
||||
const (
|
||||
finishedCt counterID = iota // 0
|
||||
workingCt // 1
|
||||
jobsCt // 2
|
||||
lastNumber // 3
|
||||
)
|
||||
|
||||
const (
|
||||
stateUnlocked uint32 = iota
|
||||
stateLocked
|
||||
)
|
||||
|
||||
var (
|
||||
setLocker = stateUnlocked
|
||||
incLocker = stateUnlocked
|
||||
decLocker = stateUnlocked
|
||||
heatLocker = stateUnlocked
|
||||
)
|
||||
|
||||
type counter struct {
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
var counters map[counterID]*counter
|
||||
|
||||
func randSleep() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
// instantiate our map
|
||||
counters = make(map[counterID]*counter)
|
||||
|
||||
// instantiate value pointer to each of our counters, referenced by it's respective counterID via our map
|
||||
for ctr := uint32(0); ctr < 4; ctr++ {
|
||||
counters[counterID(ctr)] = &counter{value: atomic.Value{}}
|
||||
// store 0 in each counter otherwise we will return nil when trying to do math and panic
|
||||
counters[counterID(ctr)].value.Store(0)
|
||||
}
|
||||
}
|
||||
|
||||
func get(ctr counterID) int {
|
||||
return counters[ctr].value.Load().(int)
|
||||
}
|
||||
|
||||
func set(ctr counterID, val int) {
|
||||
for !atomic.CompareAndSwapUint32(&setLocker, stateUnlocked, stateLocked) {
|
||||
randSleep()
|
||||
}
|
||||
defer atomic.StoreUint32(&setLocker, stateUnlocked)
|
||||
counters[ctr].value.Store(val)
|
||||
}
|
||||
|
||||
func inc(ctr counterID) {
|
||||
for !atomic.CompareAndSwapUint32(&incLocker, stateUnlocked, stateLocked) {
|
||||
randSleep()
|
||||
}
|
||||
defer atomic.StoreUint32(&incLocker, stateUnlocked)
|
||||
counters[ctr].value.Store(get(ctr) + 1)
|
||||
}
|
||||
|
||||
func dec(ctr counterID) {
|
||||
for !atomic.CompareAndSwapUint32(&decLocker, stateUnlocked, stateLocked) {
|
||||
randSleep()
|
||||
}
|
||||
defer atomic.StoreUint32(&decLocker, stateUnlocked)
|
||||
counters[ctr].value.Store(get(ctr) - 1)
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
jobChoice string
|
||||
maxWorkers = 2
|
||||
)
|
||||
|
||||
type obj struct {
|
||||
//
|
||||
}
|
||||
|
||||
var (
|
||||
finish chan struct{}
|
||||
done chan struct{}
|
||||
jobChan chan struct{}
|
||||
start chan struct{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
usage := func() {
|
||||
println("syntax: " + os.Args[0] + " <job1|job2> <workers>")
|
||||
os.Exit(0)
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
if os.Args[1] != "job1" && os.Args[1] != "job2" {
|
||||
usage()
|
||||
}
|
||||
jobChoice = os.Args[1]
|
||||
maxWorkers, err = strconv.Atoi(os.Args[2])
|
||||
if err != nil {
|
||||
usage()
|
||||
}
|
||||
finish = make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
jobChan = make(chan struct{})
|
||||
start = make(chan struct{})
|
||||
|
||||
seen = make(map[int]bool)
|
||||
}
|
||||
|
||||
func checkHeat() {
|
||||
if !atomic.CompareAndSwapUint32(&heatLocker, stateUnlocked, stateLocked) {
|
||||
return
|
||||
}
|
||||
defer atomic.StoreUint32(&heatLocker, stateUnlocked)
|
||||
// if working is zero, and finished is greater (hopefully not) or more likely equal to jobs, we are done
|
||||
if get(workingCt) == 0 && get(finishedCt) >= get(jobsCt) {
|
||||
// this will pop out at the bottom of main, allowing execution to complete and the program to exit
|
||||
finish <- obj{}
|
||||
}
|
||||
}
|
||||
|
||||
func bigHomie() {
|
||||
<-start
|
||||
for {
|
||||
select {
|
||||
// job finished
|
||||
case <-done:
|
||||
// decrement working count
|
||||
dec(workingCt)
|
||||
// increase finished count
|
||||
inc(finishedCt)
|
||||
case <-jobChan:
|
||||
go work()
|
||||
default:
|
||||
// check if we're done
|
||||
checkHeat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func work() {
|
||||
for {
|
||||
// we're at maximum capacity, don't start any new jobs
|
||||
if get(workingCt) >= maxWorkers {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
// room for more workers available, continue execution
|
||||
break
|
||||
}
|
||||
// increase working count
|
||||
inc(workingCt)
|
||||
switch jobChoice {
|
||||
case "job1":
|
||||
go job1(get(jobsCt) - get(finishedCt))
|
||||
case "job2":
|
||||
go job2()
|
||||
default:
|
||||
panic("uhh? that job doesn't exist")
|
||||
}
|
||||
}
|
||||
|
||||
var seen map[int]bool
|
||||
var seenLock = stateUnlocked
|
||||
|
||||
func job1(input int) {
|
||||
var ok bool
|
||||
for !atomic.CompareAndSwapUint32(&seenLock, stateUnlocked, stateLocked) {
|
||||
randSleep()
|
||||
}
|
||||
if _, ok = seen[input]; !ok {
|
||||
seen[input] = true
|
||||
print(input)
|
||||
print(" ")
|
||||
}
|
||||
atomic.StoreUint32(&seenLock, stateUnlocked)
|
||||
|
||||
// sleep just for visual effect
|
||||
time.Sleep(1 * time.Second)
|
||||
done <- obj{}
|
||||
}
|
||||
|
||||
func job2() {
|
||||
fmt.Println(time.Now())
|
||||
done <- obj{}
|
||||
}
|
||||
|
||||
func main() {
|
||||
go bigHomie()
|
||||
for n := 0; n < 100; n++ {
|
||||
inc(jobsCt)
|
||||
go func() {
|
||||
jobChan <- obj{}
|
||||
}()
|
||||
}
|
||||
println("\nrunning " + os.Args[1] + " with " + os.Args[2] + " worker(s)\n")
|
||||
if os.Args[1] == "job1" {
|
||||
print("remaining jobs: ")
|
||||
}
|
||||
start <- obj{}
|
||||
<-finish
|
||||
print("\n\ndone")
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
jobChoice string
|
||||
maxWorkers = 2
|
||||
finished int
|
||||
working int
|
||||
jobs int
|
||||
l *sync.RWMutex
|
||||
)
|
||||
|
||||
type obj struct {
|
||||
//
|
||||
}
|
||||
|
||||
var (
|
||||
finish chan struct{}
|
||||
done chan struct{}
|
||||
jobChan chan struct{}
|
||||
start chan struct{}
|
||||
)
|
||||
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
usage := func() {
|
||||
println("syntax: " + os.Args[0] + " <job1|job2> <workers>")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
if os.Args[1] != "job1" && os.Args[1] != "job2" {
|
||||
usage()
|
||||
}
|
||||
|
||||
jobChoice = os.Args[1]
|
||||
maxWorkers, err = strconv.Atoi(os.Args[2])
|
||||
if err != nil {
|
||||
usage()
|
||||
}
|
||||
|
||||
finish = make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
jobChan = make(chan struct{})
|
||||
start = make(chan struct{})
|
||||
l = &sync.RWMutex{}
|
||||
}
|
||||
|
||||
func checkHeat() {
|
||||
l.RLock()
|
||||
defer l.RUnlock()
|
||||
if working == 0 && finished >= jobs {
|
||||
finish <- obj{}
|
||||
}
|
||||
}
|
||||
|
||||
func bigHomie() {
|
||||
<-start
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
l.Lock()
|
||||
working--
|
||||
finished++
|
||||
l.Unlock()
|
||||
case <-jobChan:
|
||||
go work()
|
||||
default:
|
||||
checkHeat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func work() {
|
||||
for {
|
||||
l.RLock()
|
||||
if working > maxWorkers {
|
||||
l.RUnlock()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
l.RUnlock()
|
||||
break
|
||||
}
|
||||
l.Lock()
|
||||
working++
|
||||
switch jobChoice {
|
||||
case "job1":
|
||||
go job1(jobs - finished)
|
||||
case "job2":
|
||||
go job2()
|
||||
}
|
||||
l.Unlock()
|
||||
}
|
||||
|
||||
func job1(input int) {
|
||||
l.Lock()
|
||||
|
||||
if input != lastcount {
|
||||
print(input)
|
||||
print(" ")
|
||||
}
|
||||
|
||||
lastcount = input
|
||||
l.Unlock()
|
||||
|
||||
// sleep just for visual effect
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
done <- obj{}
|
||||
}
|
||||
|
||||
func job2() {
|
||||
fmt.Println(time.Now())
|
||||
// sleep just for visual effect
|
||||
done <- obj{}
|
||||
}
|
||||
|
||||
func main() {
|
||||
go bigHomie()
|
||||
for n := 0; n < 100; n++ {
|
||||
jobs++
|
||||
go func() {
|
||||
jobChan <- obj{}
|
||||
}()
|
||||
}
|
||||
println("\nrunning " + os.Args[1] + " with " + os.Args[2] + " worker(s)\n")
|
||||
if os.Args[1] == "job1" {
|
||||
print("remaining jobs: ")
|
||||
}
|
||||
start <- obj{}
|
||||
<-finish
|
||||
print("\n\ndone")
|
||||
}
|
Loading…
Reference in New Issue