why does my go channel get blocked ? (deadlock) - concurrency

It seems that the "complex" (getC) function is blocked. I assume the channel is destroyed once it is read therefore I'm wondering how can I share the sC channel with both getC function and the main function without get into deadlock ( current snippet )
package main
func main() {
//simple function and complex function/channel
sC := make(chan string)
go getS(sC)
cC := make(chan string)
go getC(sC, cC)
//collect the functions result
s := <-sC
//do something with `s`. We print but we may want to use it in a `func(s)`
print(s)
//after a while we do soemthing with `c`
c := <-cC
print(c)
}
func getS(sC chan string) {
s := " simple completed "
sC <- s
}
func getC(sC chan string, cC chan string) {
//we do some complex stuff
print("complex is not complicated\n")
//Now we need the simple value so we try wait for the s channel.
s := <-sC
c := s + " more "
cC <- c //send complex value
}

You should not try to get value from sC channel in main function because the only value you send to it is consumed by getC function in seperate go routine. While trying to read sC channel main function blocks waiting for something and it never ends. Go routine getS is finished, go routine getC has consumed value from channel sC and has also finished. There is nothing in channel sC anymore.
The possible solution is to create another channel s2C and send to it value received from sC channel.
The complete correct code would look like this:
package main
func main() {
sC := make(chan string)
go getS(sC)
s2C := make(chan string)
cC := make(chan string)
go getC(s2C, cC)
s := <-sC
println(s)
s2C <- s
c := <-cC
println(c)
}
func getS(sC chan string) {
s := " simple completed "
sC <- s
}
func getC(sC chan string, cC chan string) {
s := <-sC
c := s + " more "
cC <- c
}

I should have sent s from getS. Code below
package main
import "time"
func main() {
//simple function and complex function/channel
sC := make(chan string)
go getS(sC)
cC := make(chan string)
go getC(sC, cC)
//collect the functions result
s := <-sC
//do something with `s`. We print but we may want to use it in a `func(s)`
print(s)
//after a while we do soemthing with `c`
c := <-cC
print(c)
}
func getS(sC chan string) {
s := " simple completed \n"
sC <- s
print("sent s back so that main can read it too")
sC <- s
}
func getC(sC chan string, cC chan string) {
time.Sleep(1 * time.Second)
//we do some complex stuff
print("complex is not complicated\n")
//Now we need the simple value so we try wait for the s channel.
s := <-sC
c := s + " more "
cC <- c //send complex value
}

I think the problem is with the synchronization. Using a sleep may solve the problem. When you send a value on a channel, it should be received on the other end or else it will show deadlock error.
package main
import "sync"
import "time"
import "fmt"
var wg sync.WaitGroup
func main() {
sC := make(chan string)
wg.Add(1)
go getS(sC)
cC := make(chan string)
wg.Add(1)
go getC(sC, cC)
time.Sleep(1 * time.Millisecond)
select {
case s := <-sC:
print(s)
case c := <-cC:
print(c)
}
wg.Wait()
}
func getS(sC chan string) {
defer wg.Done()
s := " simple completed "
fmt.Println(s)
sC <- s
}
func getC(sC chan string, cC chan string) {
defer wg.Done()
fmt.Println("complex is not complicated\n")
s := <-sC
c := s + " more "
cC <- c //send complex value
}

Related

(SOLVED) Exception from HRESULT: 0x800A01A8 Dynamic Navision 2016

I wrote a code where user filters a source number from the table, the code get the source number and open an Excel file with the same number in a folder, write other data into the file and then save to temp folder. The program worked for some of the Excel files in the folder, but it won't work for the majority of the files. When it finishes running it'll say Exception from HRESULT: 0x800A01A8, the file gets saved into temp folder but the data is not written into it.
https://i.stack.imgur.com/kHtbC.png
I have searched all over Google but it seems like no one had encountered the same issue as I am and I have no idea what this exception means. Below is the code.
ProductionOrder - OnAfterGetRecord()
CLEAR(xlApplication);
CLEAR(xlWorkbooks);
CLEAR(xlWorksheet);
CLEAR(xlshape);
// Open excel
IF CREATE(xlApplication, FALSE, TRUE) THEN BEGIN
xlApplication.SheetsInNewWorkbook := 1;
xlApplication.ScreenUpdating(TRUE);
xlWorkbooks := xlApplication.Workbooks;
END ELSE ERROR('Could not start Excel.');
xlWorkbooks.Open('C:\PROCESS CHECKSHEET\' + ProductionOrder."Source No." + '.xlsx');
xlWorkbook := xlApplication.ActiveWorkbook;
xlSheets := xlWorkbook.Worksheets;
FOR i := 1 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(i);
xlWorksheet.Activate;
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
xlWorkbook._SaveAs('C:\temp\' + ProductionOrder."Source No.");
xlWorkbook.Close(TRUE);
xlApplication.Quit;
END;
CurrReport.QUIT;
LOCAL xlsCol(col : Integer) : Text
IF col > 26 THEN BEGIN
ColFirst := col DIV 26;
col := col MOD 26;
END
ELSE
ColFirst := 0;
Letters := 'ABCDEFGHIJKLMNOPQRSTUVYWXYZ';
IF ColFirst <> 0 THEN
EXIT (STRSUBSTNO('%1%2',Letters[ColFirst],Letters[col]))
ELSE
EXIT (STRSUBSTNO('%1',Letters[col]));
LOCAL xlsCell(col : Integer;row : Integer) : Text[15]
EXIT (STRSUBSTNO('%1%2',xlsCol(col),row));
Edit:
I have tried to debug. Debugger says error is on line "xlWorksheet := xlSheets.Item(i);". There is only one sheet in the Excel file that I am trying to access. What I don't understand is that it would work on other Excel files, just not on this file that I am currently trying to access.
I also found out that if I copy the content into a new Excel file, then the code would work on the new Excel file. Could it also be a problem of Excel version?
I solved this on my own.
Because the Excel files were given to me by my HOD at work (and these Excel files were written by other department), I did not know that there was a hidden sheet inside those Excel files, hence it output the exception error because my code was only indexing Excel file that only has one sheet. I changed my index to 2 and it worked. Note to self, next time gotta check for hidden sheets.
I don't know if there is a for each sheet equivalent for C/AL programming because I'm new to the language, so I used 2 for loops to solve the problem.
CLEAR(xlApplication);
CLEAR(xlWorkbooks);
CLEAR(xlWorksheet);
IF CREATE(xlApplication, FALSE, TRUE) THEN BEGIN
xlApplication.SheetsInNewWorkbook := 1;
xlApplication.ScreenUpdating(TRUE);
xlWorkbooks := xlApplication.Workbooks;
END ELSE ERROR('Could not start Excel.');
xlWorkbooks.Open('C:\13. PROCESS CHECKSHEET\' + ProductionOrder."Source No." + '.xlsx');
xlWorkbook := xlApplication.ActiveWorkbook;
xlSheets := xlWorkbook.Worksheets;
FOR I := 1 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(I);
xlWorksheet.Activate;
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
END;
FOR I := 2 TO xlSheets.Count DO BEGIN
xlWorksheet := xlSheets.Item(I);
xlWorksheet.Activate;
IF (FORMAT(xlWorksheet.Name) = 'PROCESS CHECKSHEET') OR (FORMAT(xlWorksheet.Name) = 'Process Checksheet') THEN BEGIN
xlRange := xlWorksheet.Range(xlsCell(14,7));
xlRange.Value := ProductionOrder."No.";
xlRange := xlWorksheet.Range(xlsCell(14,8));
xlRange.Value := FORMAT(ProductionOrder.Quantity);
END;
END;
xlWorkbook.SaveAs('C:\13. PROCESS CHECKSHEET\temp\' + ProductionOrder."Source No.");
MESSAGE('Success');
xlWorkbook.Close(TRUE);
xlApplication.Quit;
CurrReport.QUIT;

Confused about signature creation process (in GoLang)

I am trying to making my own signature system, just for the challenge sake. I have done like 3/4 of it.
Canonical string and String-to-sign is matching with what they except, so I will only post my signature calculation part.
signature := hmac.New(sha256.New, kSigningSum)
signature.Write([]byte(stringToSign))
signatureSum := signature.Sum(nil)
var signatureSumHexed = make([]byte, hex.EncodedLen(len(signatureSum)))
I am trying to set kSigningSum as key, and stringToSign as value, as its documented.
kSigningSum:
kSecret := AppCred.IAMSecretAccess
kDate := hmac.New(sha256.New, []byte("AWS4"+kSecret))
kDate.Write([]byte(time.Now().UTC().Format("20060102")))
kDateSum := kDate.Sum(nil)
kRegion := hmac.New(sha256.New, kDateSum)
kRegion.Write([]byte("us-east-1"))
kRegionSum := kRegion.Sum(nil)
kService := hmac.New(sha256.New, kRegionSum)
kService.Write([]byte("execute-api"))
kServiceSum := kService.Sum(nil)
kSigning := hmac.New(sha256.New, []byte("aws4_request"))
kSigning.Write(kServiceSum)
kSigningSum := kSigning.Sum(nil)
this is basically
kSigningSum = HMAC(HMAC(HMAC(HMAC("AWS4" +
kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request")
AuthHeader:
var authHeader = fmt.Sprintf("AWS4-HMAC-SHA256 Credential=%s, SignedHeaders=%s, Signature=%x, X-Amz-Date=%s", AppCred.IAMClientID+"/"+credentialScope, signedHeaders, signatureSumHexed, GetTime())
I cant understand what I am doing wrong. stringToSign is String-to-sign and it is correct, 1:1 match with what Amazon expects so data is correct. There is something wrong with kSigningSum and cant understand it. help?

golang append to 2d slice

I'm trying to create slice of slices.
In all the examples the inner slices are integer based.
I'm trying to create a slice of string slices.
Example:
[
[Name1,State1,Tags.Owner1]
[Name2,State2,Tags.Owner2]
[Name3,State3,Tags.Owner3]
]
I'm trying to do it this way:
outerList := [][]string{}
i := 0
for _,c := range clusters {
input := &eks.DescribeClusterInput{
Name: aws.String(c),
}
resp,err := svc.DescribeCluster(input)
if err != nil {
errorOut(`clusterData function: `+err.Error())
}
record := resp.Cluster
data,_ := json.Marshal(record)
error := json.Unmarshal(data, &cluster)
if error != nil {errorOut(error.Error())}
innerList := [...]string{cluster.Name,cluster.Tags["Vsad"],cluster.Status}
outerList[string(i)] = innerList
}
I get the below error:
non-integer slice index string(i)
cannot use innerList (type [3]string) as type []string in assignment
I know in Python I can simply do:
outerList = list()
for c in cluster:
a = [c.Name,c.State,c.Tags.Owner]
outerList.append(a)
You can use append. Formatted as follows:
// make room for clusters
outerList := make([][]string, len(clusters))
// iterate and fill cluster data
for i, c := range clusters {
// some processing where cluster variable is setupped
// add new inner slice
outerList[i] = append(outerList[i], cluster.Name, cluster.Tags["Vsad"], cluster.Status)
}

Why doesn't Pascal FC want to run this code with monitors?

I'm programming concurrency in Pascal-FC using Eclipse Gavab 2.0. I haven't had any problems so far using it, as it always inform me of which the errors are when it's unable to execute a program.
I did the producer-consumer problem using semaphores and it worked alright. Now I've done it using a monitor, but when I run it, it launches for a second then stops, and does nothing else. It shows no errors at all, and I can't find anything wrong with the code. Is it a compiler's problem?
Producer-Consumer using semaphores:
program ProdCons;
const MAXDATOS = 10;
{ Creamos el buffer de comunicaciĆ³n: }
type tBuffer = record
datos : array [1..MAXDATOS] of integer;
posInser, posSacar : integer;
nProductos, nHuecos, em : semaphore;
end;
var buffer : tBuffer;
{ METODOS O PROCEDIMIENTOS: }
procedure inicializar(var buffer : tBuffer);
begin
buffer.posInser := 1;
buffer.posSacar := 1;
initial(buffer.nProductos,0);
initial(buffer.nHuecos,MAXDATOS);
initial(buffer.em,1);
end;
procedure insertar(dato : integer; var buffer : tBuffer);
begin
wait(buffer.nHuecos); {En num de huecos debe ser >0}
wait(buffer.em);
buffer.datos[buffer.posInser] := dato;
writeln('Inserta dato ',dato,' en datos[',buffer.posInser,']');
buffer.posInser := buffer.posInser MOD MAXDATOS + 1;
signal(buffer.em);
signal(buffer.nProductos); {Confirmamos que num. productos >0}
end;
procedure sacar(dato : integer; var buffer : tBuffer);
begin
wait(buffer.nProductos); {Esperamos a que num. productos >0}
wait(buffer.em);
dato:=buffer.datos[buffer.posSacar];
writeln('Consume dato ',dato,' en datos[',buffer.posSacar,']');
buffer.posSacar := buffer.posSacar MOD MAXDATOS + 1;
signal(buffer.em);
signal(buffer.nHuecos);
end;
{ PROCESOS TIPO: }
process type tProductor(var buffer : tBuffer);
var dato : integer;
begin
repeat
dato := random(200);
insertar(dato,buffer);
forever
end;
process type tConsumidor(var buffer : tBuffer);
var dato : integer;
begin
repeat
sacar(dato,buffer);
forever
end;
{ Variables: }
var i : integer;
prod : array [1..5] of tProductor;
cons : array [1..3] of tConsumidor;
begin
inicializar(buffer);
cobegin
for i:=1 to 5 do
prod[i](buffer);
for i:=1 to 3 do
cons[i](buffer);
coend;
end.
Producer-Consumer with semaphore's output
Producer-Consumer using a monitor:
program ProdConsMONITORES;
const N = 5;
monitor ProdCons;
export produce, consume;
{Variables}
var posProd, posCons, cont : integer;
obj : array [1..N] of integer;
vacio, lleno : condition;
{Procedimientos/metodos}
procedure produce(dato,i : integer);
begin
if cont=N then delay(lleno);
obj[posProd] := dato;
writeln('Productor',i,' produce dato ',dato,' en obj[',posProd,']');
posProd := posProd MOD N + 1;
cont := cont + 1;
writeln(' [',cont,' objetos disponibles]');
resume(vacio);
end;
procedure consume(j : integer);
var dato := integer;
begin
if cont=0 then delay(vacio);
dato := obj[posCons];
writeln('Consumidor',j,' consume dato ',dato,' en obj[',posCons,']');
posCons := posCons MOD N + 1;
cont := cont - 1;
writeln(' [',cont,' objetos disponibles]');
resume(lleno);
end;
{Procesos}
process type Productor(i : integer);
var dato : integer;
begin
dato := random(10);
ProdCons.produce(dato,i);
end;
process type Consumidor(j : integer);
begin
ProdCons.consume(j);
end;
{Variables locales}
var p : array [1..5] of Productor;
var c : array [1..3] of Consumidor;
var i,j : integer;
begin
cont := 0;
posProd := 1; posCons := 1;
cobegin
writeln('hola');
for i:=1 to 5 do
p[i](i);
for j:=1 to 3 do
c[j](j);
coend;
end.
Producer-Consumer with monitor's output
Just in case someone else has this problem: the error was I didn't create the body of the monitor, which is a "begin-end" where variables are initialized. It must be placed right after the procedures and goes like this:
begin
cont := 0;
posProd := 1; posCons := 1;
end;
Obviously it's no longer necesary to initialize vars. at the last begin-end.

How to update field value in a Go template

I have the following case, where I am passing a struct containing a map to a template:
package main
import (
"log"
"os"
"text/template"
)
var fns = template.FuncMap{
"plus1": func(x int) int {
return x + 1
},
}
type codec struct {
Names map[string]string
Count int
}
func main() {
a := map[string]string{"one": "1",
"two": "2",
"three": "3"}
t := template.Must(template.New("abc").Funcs(fns).Parse(`{{$l := len .Names}}{{range $k, $v := .Names}}{{if ne (plus1 $.Count) $l}}{{$k}} {{$v}} {{end}}{{end}}.`))
err := t.Execute(os.Stdout, codec{a, 0})
if err != nil {
log.Println(err)
}
}
I would like to increment the Count field of codec so that I can know how many items of the map I've seen.
One solution is to make the plus1 function a closure that acts directly on the value of the codec:
// first create a codec instance
c := codec {a, 0}
// now define the function as a closure with a reference to c
fns := template.FuncMap{
"plus1": func() int {
c.Count++
return c.Count
},
}
// now we don't need to pass anything to it in the template
t := template.Must(template.New("abc").Funcs(fns).Parse(`{{$l := len .Names}}{{range $k, $v := .Names}}{{if ne (plus1) $l}}{{$k}} {{$v}} {{end}}{{end}}.`))
The output was:
one 1 three 3
which I'm guessing is what you were aiming for? And the value is retained in c at the end of execution.
You can simply define a method on your struct:
type codec struct {
Names map[string]string
Count int
}
func (c *codec) IncAndGet() int {
c.Count++
return c.Count
}
Calling it from a template:
c := &codec{Count: 2}
t := template.Must(template.New("").Parse(`{{.IncAndGet}} {{.IncAndGet}}`))
t.Execute(os.Stdout, c)
Output (try it on the Go Playground):
3 4
Note that for this to work, the method needs a pointer receiver (func (c *codec) IncAndGet()) and you have to pass a pointer to Template.Execute() (c is a pointer in our example: c := &codec{Count: 2}).
If you don't want any result just counting, define it to have a string return type and return the empty string "":
func (c *codec) Inc() string {
c.Count++
return ""
}