1
0
mirror of https://github.com/yunginnanet/unWaitgroups synced 2024-06-16 03:59:15 +00:00
unWaitGroups/atomic/main.go
2021-09-24 18:47:39 -07:00

146 lines
2.6 KiB
Go

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")
}