The Go language Chan

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Chan is a FIFO queue, and Chan is divided into two types of synchronous and asynchronous
Synchronous Chan completes the process of transmitting elements between the sender and the recipient by hand, and must require the other person's presence to complete a send or receive
The asynchronous Chan send and receive is based on Chan's cache, but when the cache queue fills up, the sender enters the send queue, and when the cache queue is empty, the recipient accesses the waiting queue.

Chan's data structure:

structHchan{    uintgoqcount;// total data in the q    uintgodataqsiz;// size of the circular q    uint16elemsize;    uint16pad;// ensures proper alignment of the buffer that follows Hchan in memory    boolclosed;    Alg*elemalg;// interface for element type    uintgosendx;// send index    uintgorecvx;// receive index    WaitQrecvq;// list of recv waiters    WaitQsendq;// list of send waiters    Lock;};

Chan Send

Voidruntime chansend (Chantype *t, Hchan *c, byte *ep, bool *pres, void *pc) {Sudog *sg;    Sudog Mysg;    g* GP;     Int64 t0;    if (c = = nil) {used (t);    if (pres! = nil) {*pres = false;    Return    } Runtime Park (nil, nil, "Chan Send (Nil chan)");  Return Not reached} if (Debug) {runtime printf ("chansend:chan=%p;    Elem= ", c);    C->elemalg->print (C->elemsize, EP);    Runtime prints ("\ n");    } t0 = 0;    Mysg.releasetime = 0;    if (runtime blockprofilerate > 0) {t0 = runtime cputicks ();    Mysg.releasetime =-1;    } Runtime Lock (c);    if (raceenabled) runtime racereadpc (c, PC, runtime Chansend);     if (c->closed) goto closed;     if (C->dataqsiz > 0) goto asynch;    sg = dequeue (&C->RECVQ);    if (sg! = nil) {if (raceenabled) Racesync (c, SG);     runtime unlock (c);    GP = sg->g;    Gp->param = SG;    if (Sg->elem! = nil) c->elemalg->copy (C->elemsize, Sg->elem, EP); if (SG->releasetime) Sg->releasetime = Runtime cputicks ();     Runtime ready (GP);    if (pres! = nil) *pres = true;    Return    } if (pres! = nil) {runtime unlock (c);    *pres = false;    Return    } Mysg.elem = EP;    MYSG.G = g;    Mysg.selgen = Noselgen;    G->param = nil;    Enqueue (&C->SENDQ, &MYSG);     Runtime Park (runtime unlock, C, "Chan send");    if (G->param = = nil) {Runtime lock (c);    if (!c->closed) runtime throw ("Chansend:spurious wakeup");    Goto closed;     } if (Mysg.releasetime > 0) Runtime blockevent (mysg.releasetime-t0, 2); Return     Asynch:if (c->closed) goto closed;    if (C->qcount >= c->dataqsiz) {if (pres! = nil) {runtime unlock (c);    *pres = false;    Return    } MYSG.G = g;    Mysg.elem = nil;    Mysg.selgen = Noselgen;    Enqueue (&C->SENDQ, &MYSG);     Runtime Park (runtime unlock, C, "Chan send");    Runtime Lock (c);    Goto Asynch;  } if (raceenabled)  Runtime Racerelease (Chanbuf (c, c->sendx));    C->elemalg->copy (C->elemsize, Chanbuf (c, C->sendx), EP);    if (++c->sendx = = c->dataqsiz) c->sendx = 0;     c->qcount++;    sg = dequeue (&C->RECVQ);    if (sg! = nil) {GP = sg->g;    runtime unlock (c);    if (sg->releasetime) sg->releasetime = Runtime cputicks ();    Runtime ready (GP);    } else Runtime unlock (c);    if (pres! = nil) *pres = true;    if (Mysg.releasetime > 0) Runtime blockevent (mysg.releasetime-t0, 2); Return    Closed:runtime unlock (c); Runtime panicstring ("Send on closed channel");}
    1. To determine the queue type, the asynchronous queue goes to 5
    2. Get recipients in the wait queue from the wait queue
    3. If the recipient is taken, the object is passed directly to the recipient, then the recipient is awakened, the sending process is complete
    4. If the recipient is not taken, the sender is enqueue to the Send queue and the sender enters a blocking state
    5. Asynchronous queues first determine if the queue cache still has space
    6. If the cache space is full, the sender is enqueue to the Send queue and the sender enters a blocking state
    7. If the cache space is not full, the element is copied to the cache, and the sender does not enter a blocking state
    8. Attempt to wake up a recipient in the wait queue

Chan accepts

Voidruntime chanrecv (Chantype *t, hchan* C, byte *ep, bool *selected, bool *received) {Sudog *sg;    Sudog Mysg;    G *GP;     Int64 t0;     if (debug) Runtime printf ("Chanrecv:chan=%p\n", c);    if (c = = nil) {used (t);    if (Selected! = nil) {*selected = false;    Return    } Runtime Park (nil, Nil, "Chan receive (Nil Chan)");  Return    Not reached} t0 = 0;    Mysg.releasetime = 0;    if (runtime blockprofilerate > 0) {t0 = runtime cputicks ();    Mysg.releasetime =-1;    } Runtime Lock (c);     if (C->dataqsiz > 0) goto asynch;     if (c->closed) goto closed;    sg = dequeue (&AMP;C-&GT;SENDQ);    if (sg! = nil) {if (raceenabled) Racesync (c, SG);     runtime unlock (c);    if (ep! = nil) c->elemalg->copy (C->elemsize, EP, Sg->elem);    GP = sg->g;    Gp->param = SG;    if (sg->releasetime) sg->releasetime = Runtime cputicks ();     Runtime ready (GP);    if (Selected! = nil) *selected = true; if (received = nil) *received = true;    Return    } if (selected! = nil) {runtime unlock (c);    *selected = false;    Return    } Mysg.elem = EP;    MYSG.G = g;    Mysg.selgen = Noselgen;    G->param = nil;    Enqueue (&AMP;C-&GT;RECVQ, &AMP;MYSG);     Runtime Park (runtime unlock, C, "Chan receive");    if (G->param = = nil) {Runtime lock (c);    if (!c->closed) runtime throw ("Chanrecv:spurious wakeup");    Goto closed;    } if (Received! = nil) *received = true;    if (Mysg.releasetime > 0) Runtime blockevent (mysg.releasetime-t0, 2); Return     Asynch:if (c->qcount <= 0) {if (c->closed) goto closed;    if (Selected! = nil) {runtime unlock (c);    *selected = false;    if (Received! = nil) *received = false;    Return    } MYSG.G = g;    Mysg.elem = nil;    Mysg.selgen = Noselgen;    Enqueue (&AMP;C-&GT;RECVQ, &AMP;MYSG);     Runtime Park (runtime unlock, C, "Chan receive");    Runtime Lock (c);    Goto Asynch; } if (Raceenabled) Runtime Raceacquire (Chanbuf (c, C-&GT;RECVX));    if (ep! = nil) c->elemalg->copy (C->elemsize, EP, Chanbuf (C, C-&GT;RECVX));    C->elemalg->copy (C->elemsize, Chanbuf (c, C-&GT;RECVX), nil);    if (++C-&GT;RECVX = = c->dataqsiz) C-&GT;RECVX = 0;     c->qcount--;    sg = dequeue (&AMP;C-&GT;SENDQ);    if (sg! = nil) {GP = sg->g;    runtime unlock (c);    if (sg->releasetime) sg->releasetime = Runtime cputicks ();    Runtime ready (GP);     } else Runtime unlock (c);    if (Selected! = nil) *selected = true;    if (Received! = nil) *received = true;    if (Mysg.releasetime > 0) Runtime blockevent (mysg.releasetime-t0, 2); Return    Closed:if (ep = nil) C->elemalg->copy (C->elemsize, EP, nil);    if (Selected! = nil) *selected = true;    if (Received! = nil) *received = false;    if (raceenabled) runtime Raceacquire (c);    runtime unlock (c); if (Mysg.releasetime > 0) Runtime blockevent (mysg.releasetime -T0, 2);} 
    1. determines the queue type, and if it is an asynchronous queue, go to 5
    2. get the recipient from the Send queue
    3. If the recipient is taken, the element is fetched directly from the recipient, and the sender is awakened, and the process is completed
    4. If the recipient is not taken, enqueue itself to the wait queue, blocking goroutine waiting for the sender to wake up
    5. Async Queue First determine if there are elements in the queue cache
    6. cache is empty, it enqueue itself to the waiting queue , blocking goroutine waiting for the sender to wake up
    7. cache non-empty, remove the first element in the cache
    8. then try to wake up a sender in the Send queue

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.