I'm new to golang (whith Java concurrency background). Consider this peace of code :
package main
import "fmt"
func sendenum(num int, c chan int) {
c <- num
}
func main() {
c := make(chan int)
go sendenum(0, c)
x, y := <-c, <-c
fmt.Println(x, y)
}
When I run this code , I get this error
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/tarrsalah/src/go/src/github.com/tarrsalah/stackoverflow/chan_dead_lock.go:12 +0x90
exit status 2
I know, adding another go sendenum(0, c) statement fix the issue, ... but
When and Where the deadlock happened ?
After it receives the 0, main keeps on waiting on the receiving end of c for another value to arrive (to put in the y variable), but it never will, as the goroutine running main is the only one left to live.
When you add another go sendenum(0, c), it actually gets a value on the second channel receive, puts it into the y variable, prints x and y out and the program finishes succesfully.
It's not that "reusing" a channel is a problem. It's just a simple deadlock happening because the code prescribes two reads, but only one write to the same channel. The second read can never happen, hence the deadlock.
Related
first of all I know my question look familiar but I am actually not asking why a seg-fault occurs when sharing a lua state between different pthread. I am actually asking why they don't seg-fault in a specific case described below.
I tried to organize it as well as I could but I realize it is very long. Sorry about that.
A bit of background:
I am writing a program which is using the Lua interpreter as a base for the user to execute instructions and using the ROOT libraries (https://root.cern.ch/) to display graphs, histograms, etc...
All of this is working just fine but then I tried to implement a way for the user to start a background task while keeping the ability to input commands in the Lua prompt, to be able to do something else entirely while the task finishes, or to request to stop it for instance.
My first attempt was the following:
First on the Lua side I load some helper functions and initialize global variables
-- Lua script
RootTasks = {}
NextTaskToStart = nil
function SetupNewTask(taskname, fn, ...)
local task = function(...)
local rets = table.pack(fn(...))
RootTasks[taskname].status = "done"
return table.unpack(rets)
end
RootTasks[taskname] = {
task = SetupNewTask_C(task, ...),
status = "waiting",
}
NextTaskToStart = taskname
end
Then on the C side
// inside the C++ script
int SetupNewTask_C ( lua_State* L )
{
// just a function to check if the argument is valid
if ( !CheckLuaArgs ( L, 1, true, "SetupNewTask_C", LUA_TFUNCTION ) ) return 0;
int nvals = lua_gettop ( L );
lua_newtable ( L );
for ( int i = 0; i < nvals; i++ )
{
lua_pushvalue ( L, 1 );
lua_remove ( L, 1 );
lua_seti ( L, -2, i+1 );
}
return 1;
}
Basically the user provide the function to execute followed by the parameters to pass and it just pushes a table with the function to execute as the first field and the arguments as subsequent fields. This table is pushed on top of the stack, I retrieve it and store it a global variable.
The next step is on the Lua side
-- Lua script
function StartNewTask(taskname, fn, ...)
SetupNewTask(taskname, fn, ...)
StartNewTask_C()
RootTasks[taskname].status = "running"
end
and on the C side
// In the C++ script
// lua, called below, is a pointer to the lua_State
// created when starting the Lua interpreter
void* NewTaskFn ( void* arg )
{
// helper function to get global fields from
// strings like "something.field.subfield"
// Retrieve the name of the task to be started (has been pushed as
// a global variable by previous call to SetupNewTask_C)
TryGetGlobalField ( lua, "NextTaskToStart" );
if ( lua_type ( lua, -1 ) != LUA_TSTRING )
{
cerr << "Next task to schedule is undetermined..." << endl;
return nullptr;
}
string nextTask = lua_tostring ( lua, -1 );
lua_pop ( lua, 1 );
// Now we get the actual table with the function to execute
// and the arguments
TryGetGlobalField ( lua, ( string ) ( "RootTasks."+nextTask ) );
if ( lua_type ( lua, -1 ) != LUA_TTABLE )
{
cerr << "This task does not exists or has an invalid format..." << endl;
return nullptr;
}
// The field "task" from the previous table contains the
// function and arguments
lua_getfield ( lua, -1, "task" );
if ( lua_type ( lua, -1 ) != LUA_TTABLE )
{
cerr << "This task has an invalid format..." << endl;
return nullptr;
}
lua_remove ( lua, -2 );
int taskStackPos = lua_gettop ( lua );
// The first element of the table we retrieved is the function so the
// number of arguments for that function is the table length - 1
int nargs = lua_rawlen ( lua, -1 ) - 1;
// That will be the function
lua_geti ( lua, taskStackPos, 1 );
// And the arguments...
for ( int i = 0; i < nargs; i++ )
{
lua_geti ( lua, taskStackPos, i+2 );
}
lua_remove ( lua, taskStackPos );
// I just reset the global variable NextTaskToStart as we are
// about to start the scheduled one.
lua_pushnil ( lua );
TrySetGlobalField ( lua, "NextTaskToStart" );
// Let's go!
lua_pcall ( lua, nargs, LUA_MULTRET, 0 );
}
int StartNewTask_C ( lua_State* L )
{
pthread_t newTask;
pthread_create ( &newTask, nullptr, NewTaskFn, nullptr );
return 0;
}
So for instance a call in the Lua interpreter to
> StartNewTask("PeriodicPrint", function(str) for i=1,10 print(str);
>> sleep(1); end end, "Hello")
Will produce for the next 10 seconds a print of "Hello" every second. It will then return from execution and everything is wonderful.
Now if I ever hit ENTER key while that task is running, the program dies in horrible seg-fault sufferings (which I don't copy here as each time it seg-fault the error log is different, sometimes there is no error at all).
So I read a bit online what could be the matter and I found several mention that the lua_State are not thread safe. I don't really understand why just hitting ENTER will make it flip out but that's not really the point here.
I discovered by accident that this approach could work without any seg-faulting with a tiny modification. Instead of running the function directly, if a coroutine is executed, everything I wrote above works just fine.
replace the previous Lua side function SetupNewTask with
function SetupNewTask(taskname, fn, ...)
local task = coroutine.create( function(...)
local rets = table.pack(fn(...))
RootTasks[taskname].status = "done"
return table.unpack(rets)
end)
local taskfn = function(...)
coroutine.resume(task, ...)
end
RootTasks[taskname] = {
task = SetupNewTask_C(taskfn, ...),
routine = task,
status = "waiting",
}
NextTaskToStart = taskname
end
I can execute several tasks at once for extended period of time without getting any seg-faults. So we finally come to my question:
Why using coroutine works? What is the fundamental difference in this case? I just call coroutine.resume and I do not do any yield (or anything else for what matters). Then just wait for the coroutine to be done and that's it.
Are coroutine doing something I do not suspect?
That it seems as if nothing broke doesn't mean that it actually works, so…
What's in a lua_State?
(This is what a coroutine is.)
A lua_State stores this coroutine's state – most importantly its stack, CallInfo list, a pointer to the global_State, and a bunch of other stuff.
If you hit return in the REPL of the standard Lua interpreter, the interpreter tries to run the code you typed. (An empty line is also a program.) This involves putting it on the Lua stack, calling some functions, etc. etc. If you have code running in a different OS thread that is also using the same Lua stack/state… well, I think it's clear why this breaks, right? (One part of the problem is caching of stuff that "doesn't"/shouldn't change (but changes because another thread is also messing with it). Both threads are pushing/popping stuff on the same stack and step on each other's feet. If you want to dig through the code, luaV_execute may be a good starting point.)
So now you're using two different coroutines, and all the obvious sources of problems are gone. Now it works, right…? Nope, because coroutines share state,
The global_State!
This is where the "registry", string cache, and all the things related to garbage collection live. And while you got rid of the main "high-frequency" source of errors (stack handling), many many other "low-frequency" sources remain. A brief (non-exhaustive!) list of some of them:
You can potentially trigger a garbage collection step by any allocation, which will then run the GC for a bit, which uses its shared structures. And while allocations usually don't trigger the GC, the GCdebt counter that controls this is part of the global state, so once it crosses the threshold, allocations on multiple threads at the same time have a good chance to start the GC on several threads at once. (If that happens, it'll almost certainly explode violently.) Any allocation means, among others
creating tables, coroutines, userdata, …
concatenating strings, reading from files, tostring(), …
calling functions(!) (if that requires growing the stack or allocating a new CallInfo slot)
etc.
(Re-)Setting a thing's metatable may modify GC structures. (If the metatable has __gc or __mode, it gets added to a list.)
Adding new fields to tables, which may trigger a resize. If you're also accessing it from another thread during the resize (even just reading existing fields), well… *boom*. (Or not boom, because while the data may have moved to a different area, the memory where it was before is probably still accessible. So it might "work" or only lead to silent corruption.)
Even if you stopped the GC, creating new strings is unsafe because it may modify the string cache.
And then probably lots of other things…
Making it Fail
For fun, you can re-build Lua and #define both HARDSTACKTESTS and HARDMEMTESTS (e.g. at the very top of luaconf.h). This will enable some code that will reallocate the stack and run a full GC cycle in many places. (For me, it does 260 stack reallocations and 235 collections just until it brings up the prompt. Just hitting return (running an empty program) does 13 stack reallocations and 6 collections.) Running your program that seems to work with that enabled will probably make it crash… or maybe not?
Why it might still "work"
So for instance a call in the Lua interpreter to
StartNewTask("PeriodicPrint", function(str)
for i=1,10 print(str); sleep(1); end
end, "Hello")
Will produce for the next 10 seconds a print of "Hello" every second.
In this particular example, there's not much happening. All the functions and strings are allocated before you start the thread. Without HARDSTACKTESTS, you might be lucky and the stack is already big enough. Even if the stack needs to grow, the allocation (& collection cycle because HARDMEMTESTS) may have the right timing so that it doesn't break horribly. But the more "real work" that your test program does, the more likely it will be that it will crash. (One good way to do that is to create lots of tables and stuff so the GC needs more time for the full cycle and the time window for interesting race conditions gets bigger. Or maybe just repeatedly run a dummy function really fast like for i = 1, 1e9 do (function() return i end)() end on 2+ threads and hope for the best… err, worst.)
In my project, function clipsUpdate reads some facts which are set by CLIPS without the interference of my C++ code. Based on the read facts, clipsUpdate calls the needed function.
void updateClips(void)
{
// read clipsAction
switch(clipsAction)
{
case ActMove:
goToPosition (0, 0, clipsActionArg);
break;
}
}
In goToPosition function, a message is sent to the vehicle to move to the specified position and then a while loop is used to wait until the vehicle reaches the position.
void goToPosition(float north, float east, float down)
{
// Prepare and send the message
do
{
// Read new location information.
}while(/*Specified position reached?*/)
}
The problem is that updateClips should be called every 500 ms and when the goToPosition function is called, the execution is blocked until the target location is reached. During this waiting period, something may happen that requires the vehicle to stop. Therefore, updateClips should be called every 500 ms no matter what, and it should be able to stop executing goToPosition if it's running.
I tried using threads as following, but it didn't work successfully with me and it was difficult for me to debug. I think it can be done with a simpler and cleaner way.
case ActMove:
std::thread t1(goToPosition, 0, 0, clipsActionArg);
t1.detach();
break;
My question is, how can I check if the target location is reached without blocking the execution, i.e., without using while?
You probably want an event-driven model.
In an event-driven model, your main engine is a tight loop that reads events, updates state, then waits for more events.
Some events are time based, others are input based.
The only code that is permitted to block your main thread is the main loop, where it blocks until a timer hits or a new event arrives.
It might very roughly look like this:
using namespace std::literals::chrono_literals;
void main_loop( engine_state* state ) {
bool bContinue = true;
while(bContinue) {
update_ui(state);
while(bContinue && process_message(state, 10ms)) {
bContinue = update_state(state);
}
bContinue = update_state(state);
}
}
update_ui provides feedback to the user, if required.
process_message(state, duration) looks for a message to process, or for 10ms to occur. If it sees a message (like goToPosition), it modifies state to reflect that message (for example, it might store the desired destionation). It does not block, nor does it take lots of time.
If no message is recived in duration time, it returns anyhow without modifying state (I'm assuming you want things to happen even if no new input/messages occur).
update_state takes the state and evolves it. state might have a last updated time stamp; update_state would then make the "physics" reflect the time since last one. Or do any other updates.
The point is that process_message doesn't do work on the state (it encodes desires), while update_state advances "reality".
It returns false if the main loop should exit.
update_state is called once for every process_message call.
updateClips being called every 500ms can be encoded as a repeated automatic event in the queue of messages process_message reads.
void process_message( engine_state* state, std::chrono::milliseconds ms ) {
auto start = std::chrono::high_resolution_clock::now();
while (start + ms > std::chrono::high_resolution_clock::now()) {
// engine_state::delayed is a priority_queue of timestamp/action
// ordered by timestamp:
while (!state->delayed.empty()) {
auto stamp = state->delayed.front().stamp;
if (stamp >= std::chrono::high_resolution_clock::now()) {
auto f = state->queue.front().action;
state->queue.pop();
f(stamp, state);
} else {
break;
}
}
//engine_state.queue is std::queue<std::function<void(engine_state*)>>
if (!state->queue.empty()) {
auto f = state->queue.front();
state->queue.pop();
f(state);
}
}
}
The repeated polling is implemented as a delayed action that, as its first operation, inserts a new delayed action due 500ms after this one. We pass in the time the action was due to run.
"Normal" events can be instead pushed into the normal action queue, which is a sequence of std::function<void(engine_state*)> and executed in order.
If there is nothing to do, the above function busy-waits for ms time and then returns. In some cases, we might want to go to sleep instead.
This is just a sketch of an event loop. There are many, many on the internet.
New to Go. I'm attempting to code an "assembly line" where multiple functions act like workers and pass some data structure to each other down the line, each doing something to the data structure.
type orderStruct struct {
orderNum,capacity int
orderCode uint64
box [9]int
}
func position0(in chan orderStruct){
order := <-in
if((order.orderCode<<63)>>63 == 1){
order.box[order.capacity] = 1
order.capacity += 1
}
fmt.Println(" filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
}
func startOrder(in chan orderStruct){
order := <-in
fmt.Printf("\nStart an empty box for customer order number %d , request number %d\n", order.orderNum, order.orderCode)
fmt.Println(" starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")
d := make(chan orderStruct,1)
go position0(d)
d <- order
}
func main() {
var orders [10]orderStruct
numOrders := len(os.Args)-1
var x int
for i := 0; i < numOrders; i++{
x, _ = strconv.Atoi(os.Args[i+1])
orders[i].orderCode = uint64(x)
orders[i].orderNum = i+1
orders[i].capacity = 0
for j := 0; j < 9; j++{
orders[i].box[j] = 0
}
c := make(chan orderStruct)
go startOrder(c)
c <- orders[i]
}
}
So basically the issue I'm having is that the print statements in startOrder() execute fine, but when I try to pass the struct to position0(), nothing is printed. Am I misunderstanding how channels work?
Pipelines are a great place to start when learning to program concurrently in Go. Nick Craig-Wood's answer provides a working solution to this specific challenge.
There is a whole range of other ways to use concurrency in Go. Broadly, there are three categories divided according to what is being treated as concurrent:
Functional decomposition - Creating pipelines of several functions is a good way to get started - and is your question's topic. It's quite easy to think about and quite productive. However, if it progresses to truly parallel hardware, it's quite hard to balance the load well. Everything goes at the speed of the slowest pipeline stage.
Geometric decomposition - Dividing the data up into separate regions that can be processed independently (or without too much communication). Grid-based systems are popularly used in certain domains of scientific high-performance computing, such as weather-forecasting.
Farming - Identifying how the work to be done can be chopped into (a large number of) tasks and these tasks can be allocated to 'workers' one by one until all are completed. Often, the number of tasks far exceeds the number of workers. This category includes all the so-called 'embarrassingly parallel' problems (embarrassing because if you fail to get your high-performance system to give linear speed-up, you look a bit daft).
I could add a fourth category of hybrids of several of the above.
There is quite a lot of literature about this, including much from the days of Occam programming in the '80s and '90s. Go and Occam both use CSP message passing so the issues are similar. I would single out the helpful book Practical Parallel Processing: An introduction to problem solving in parallel (Chalmers and Tidmus 1996).
I've attempted to re-write what you've written to work properly. You can run it on the playground
The main differences are
only two go routines are started - these act as the two workers on the production line - one taking orders and the other filling boxes
use of sync.WaitGroup to find out when they end
use of for x := range channel
use of close(c) to signal end of channel
you could start multiple copies of each worker and the code would still work fine (repeat the wg.Add(1); go startOrders(c, wg) code)
Here is the code
package main
import (
"fmt"
"sync"
)
type orderStruct struct {
orderNum, capacity int
orderCode uint64
box [9]int
}
func position0s(in chan orderStruct, wg *sync.WaitGroup) {
defer wg.Done()
for order := range in {
if (order.orderCode<<63)>>63 == 1 {
order.box[order.capacity] = 1
order.capacity += 1
}
fmt.Println(" filling box {", order.orderNum, order.orderCode, order.box, order.capacity, "} at position 0")
}
}
func startOrders(in chan orderStruct, wg *sync.WaitGroup) {
defer wg.Done()
d := make(chan orderStruct)
wg.Add(1)
go position0s(d, wg)
for order := range in {
fmt.Printf("\nStart an empty box for customer order number %d , request number %d\n", order.orderNum, order.orderCode)
fmt.Println(" starting box {", order.orderNum, order.orderCode, order.box, order.capacity, "}")
d <- order
}
close(d)
}
func main() {
var orders [10]orderStruct
numOrders := 4
var x int = 10
wg := new(sync.WaitGroup)
c := make(chan orderStruct)
wg.Add(1)
go startOrders(c, wg)
for i := 0; i < numOrders; i++ {
orders[i].orderCode = uint64(x)
orders[i].orderNum = i + 1
orders[i].capacity = 0
for j := 0; j < 9; j++ {
orders[i].box[j] = 0
}
c <- orders[i]
}
close(c)
wg.Wait()
}
I would like to thank to everyone in ahead for reading this. I have a very specific issue. I need to control three USRPs simultaneously from Matlab. Here is my serial solution:
`frameLength=180;
%transmit
R=zeros(frameLength,8000);
i = 1;j = 1;k=1;nStop = 8000;
while(j<nStop) % three times of lenght of frame
step(hTx1,data1(:,i)); % Tx1 transmit data in interval i
step(hTx2,data2(:,i)); %Tx2 transmit data in interval i
[Y, LEN]=step(hRx); %receiver recieve data from Tx1 and Tx2 (but shifted)
data=Y; %just reorganzied
if mod(i,nPacket)==0 % end of column (packet, start new packet)
i = 0;
end
if LEN==frameLength %just reorganizing
R(:,k)=data;
k=k+1
if k == nStop
break; %end
end
end
i = i+1;
j = j+1
end`
This solution have one problem, its not fully synchronized because steps functions are serially executed, therefore is little delay between signals from Tx1 a Tx2 on receiver.
If iI try this with parfor, lets assume that matlabpool invoke 4 workers (cores) it give me error right on first "step" function because multiple workers try to execute same function and therefore it cause collision. Step is Matlab routine to access Universal Software Radio Peripheral (USRP). But its little complicated when one core already execute that command with argument of some USRP, that USRP is busy and other call of this command causes error.
Unfortunatelly there is no scheduling for parallel loops to assign individual "step" commands to each core.
My question is, if is there any question how to parallelize at least three steps commands with prevent cores collision? If only these three steps commands, the rest can be done serial way, it doesn't matter.
It could be done in worst case by invoking three matlab instances where every instance controls one USRP and before step command could be some external routine (like x bit counter in C for instance) to synchronize this tasks.
Ive already tried to use this semaphore routine to create barrier for every core to stop and wait before step commands. http://www.mathworks.com/matlabcentral/fileexchange/45504-semaphore-posix-and-windows
This example is shown here:
function init()
(1) exitThreads = false; % used to exit func1, func2, func3 threads.
(2)cntMutexKey = 5; % mutex for doneCnt.
(3)doneCnt = 0; % func1-3 increment this when they finish.
(4)barrierCnt = 0; %global
(5)barrierKey = 7; %global
(6)paralellTasksDoneKey = 8; %global, semaphore to tell main loop when func1-3 are done.
(7)semaphore('create', cntMutexKey, 1);
(8)semaphore('create', barrierKey, 4); %Has count of 3 for each of the three functions to execute in parallel. We want to initialize it to 0.
(9)semaphore('wait', barrierKey); %now it has 3
(10)semaphore('wait', barrierKey); %now it has 2
(11)semaphore('wait', barrierKey); %now it has 1
(12)semaphore('wait', barrierKey); %now it has 0
(13)semaphore('create', paralellTasksDoneKey, 1);
(14)semaphore('wait', paralellTasksDoneKey); %Set it to 0.
(15)funList = {#func1,#func2,#func3};
(16)matlabpool
(17)parfor i=1:length(funList) %Start 3 threads.
funList{i}();
(18)end
(jump to) mycycle(); %Now run your code.
exitThreads = true; %Tell func1-3 to exit.
end
global exitThreads
while(~exitThreads)
barrier();
step(hTx1,data1(:,l));
done();
end
end
function func2()
global exitThreads
while(~exitThreads)
barrier();
step(hTx2,data2(:,l));
done();
end
end
function func3()
global exitThreads Y LEN
while(~exitThreads)
barrier();
[Y, LEN]=step(hRx); %need [Y,LEN] global or something, and run "parfor j=1:8000" sequentially and not in paralell.
done();
end
end
(25)function barrier()
(26)semaphore('wait', cntMutexKey); %init to 1, after 3 cores increment to 4 it proceed IF
(27)barrierCnt = barrierCnt+1; %changed from barrierCnt += 1
(28)if(barrierCnt == 4) %We now know that func1,func2,func3,yourcode are all at the barrier.
(29)barrierCnt = 0; %reset count
(30)semaphore('post', cntMutexKey);
(31)semaphore('post', barrierKey); %Increment barrier count, so a func will run.
(32)semaphore('post', barrierKey); %Increment barrier count, so a func will run.
(33)semaphore('post', barrierKey); %Increment barrier count, so a func will run.
else
(34)semaphore('post', cntMutexKey);
(get stuck here)semaphore('wait', barrierKey); %Wait for other threads (the barrier).
end
end
function done()
semaphore('wait', doneKey);
doneCnt = doneCnt+ 1; %changed from doneCnt += 1
if(doneCnt == 3)
semaphore('post', paralellTasksDoneKey);
doneCnt = 0; %Reset counter.
end
semaphore('post', doneKey);
end
function mycycle()
(19) global paralellTasksDoneKey Y LEN data
(21)for j=1:8000 % three times send and recieved frame with nPackets,
(22)i=1; %example is done with this loop handled sequentially.
(23)l=1; % More complex to allow this in paralell, but its not necessary
(24)k=1;
(jump to) barrier(); %Want loop to stop here & allow func1,func2,func3 do to their work.
semaphore('wait', paralellTasksDoneKey); %Wait for func1,func2,func3 to finish.
data=Y;
if mod(i,nPacket)==0 %end of frame
i = 0;
end
if LEN==frameLength
R(:,k)=data;
k=k+1;
end
i = i+1;
l=l+1;
end
end
*Note: numbers and jumps in parenthesis indicate flow of program, step by step from debbuger. End program get stuck there (35).
Or it could be maybe done by using the OpenMP library in C, to run those commands in parallel, but I've non experience with that, Iam not so skilled programmer. viz [http://bisqwit.iki.fi/story/howto/openmp/#Sections][2]
Sorry for a little bit larger file, but I want to show you my solutions (not fully mine) because it can be helpful for anyone who read this and is more skilled. I will be thankful for any kind of help or advice. Have a nice day for all of you.
I would suggest using SPMD rather than PARFOR for this sort of problem. Inside SPMD, you can use labBarrier to synchronise the workers.
I'm sure that there is a simple explanation to this trivial situation, but I'm new to the go concurrency model.
when I run this example
package main
import "fmt"
func main() {
c := make(chan int)
c <- 1
fmt.Println(<-c)
}
I get this error :
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/tarrsalah/src/go/src/github.com/tarrsalah/tour.golang.org/65.go:8 +0x52
exit status 2
Why ?
Wrapping c <- in a goroutine makes the example run as we expected
package main
import "fmt"
func main() {
c := make(chan int)
go func(){
c <- 1
}()
fmt.Println(<-c)
}
Again, why ?
Please, I need deep explanation , not just how to eliminate the deadlock and fix the code.
From the documentation :
If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value
has been copied to the buffer; if the buffer is full, this means
waiting until some receiver has retrieved a value.
Said otherwise :
when a channel is full, the sender waits for another goroutine to make some room by receiving
you can see an unbuffered channel as an always full one : there must be another goroutine to take what the sender sends.
This line
c <- 1
blocks because the channel is unbuffered. As there's no other goroutine to receive the value, the situation can't resolve, this is a deadlock.
You can make it not blocking by changing the channel creation to
c := make(chan int, 1)
so that there's room for one item in the channel before it blocks.
But that's not what concurrency is about. Normally, you wouldn't use a channel without other goroutines to handle what you put inside. You could define a receiving goroutine like this :
func main() {
c := make(chan int)
go func() {
fmt.Println("received:", <-c)
}()
c <- 1
}
Demonstration
In unbuffered channel writing to channel will not happen until there must be some receiver which is waiting to receive the data, which means in the below example
func main(){
ch := make(chan int)
ch <- 10 /* Main routine is Blocked, because there is no routine to receive the value */
<- ch
}
Now In case where we have other go routine, the same principle applies
func main(){
ch :=make(chan int)
go task(ch)
ch <-10
}
func task(ch chan int){
<- ch
}
This will work because task routine is waiting for the data to be consumed before writes happen to unbuffered channel.
To make it more clear, lets swap the order of second and third statements in main function.
func main(){
ch := make(chan int)
ch <- 10 /*Blocked: No routine is waiting for the data to be consumed from the channel */
go task(ch)
}
This will leads to Deadlock
So in short, writes to unbuffered channel happens only when there is some routine waiting to read from channel, else the write operation is blocked forever and leads to deadlock.
NOTE: The same concept applies to buffered channel, but Sender is not blocked until the buffer is full, which means receiver is not necessarily to be synchronized with every write operation.
So if we have buffered channel of size 1, then your above mentioned code will work
func main(){
ch := make(chan int, 1) /*channel of size 1 */
ch <-10 /* Not blocked: can put the value in channel buffer */
<- ch
}
But if we write more values to above example, then deadlock will happen
func main(){
ch := make(chan int, 1) /*channel Buffer size 1 */
ch <- 10
ch <- 20 /*Blocked: Because Buffer size is already full and no one is waiting to recieve the Data from channel */
<- ch
<- ch
}
In this answer, I will try to explain the error message through which we can peek a little bit into how go works in terms of channels and goroutines
The first example is:
package main
import "fmt"
func main() {
c := make(chan int)
c <- 1
fmt.Println(<-c)
}
The error message is:
fatal error: all goroutines are asleep - deadlock!
In the code, there are NO goroutines at all (BTW this error is in runtime, not compile time). When go runs this line c <- 1, it wants to make sure that the message in the channel will be received somewhere (i.e <-c). Go does NOT know if the channel will be received or not at this point. So go will wait for the running goroutines to finish until either one of the following happens:
all of the goroutines are finished(asleep)
one of the goroutine tries to receive the channel
In case #1, go will error out with the message above, since now go KNOWS that there is no way that a goroutine will receive the channel and it need one.
In case #2, the program will continue, since now go KNOWS that this channel is received. This explain the successful case in OP's example.
Buffering removes synchronization.
Buffering makes them more like Erlang's mailboxes.
Buffered channels can be important for some problems but they are more subtle to reason about
By default channels are unbuffered, meaning that they will only accept sends
(chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value.
Buffered channels accept a limited number of
values without a corresponding receiver for those values.
messages := make(chan string, 2) //-- channel of strings buffering up to 2 values.
Basic sends and receives on channels are blocking.
However, we can use select with a default clause to implement non-blocking sends, receives, and even non-blocking multi-way selects.