usb转串口-git登录命令

queue_work
2023年4月2日发(作者:下载qq2013正式版)

【golang源码分析】chan底层原理——附带读写⽤户队列的环

形缓冲区

1环形缓冲区

1.1环形缓冲区结构

环形缓冲区通常有⼀个读指针和⼀个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动

读指针和写指针就可以实现缓冲区的数据读取和写⼊。在通常情况下,环形缓冲区的读⽤户仅仅会影响读指针,⽽写⽤户仅仅会影响写指

针。如果仅仅有⼀个读⽤户和⼀个写⽤户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写⽤户访问环形缓冲区,

那么必须添加互斥保护机制来确保多个⽤户互斥访问环形缓冲区。

1.2环形缓冲区⼀种读写实现机制

⼀般的,圆形缓冲区需要4个指针

在内存中实际开始位置;

在内存中实际结束位置,也可以⽤缓冲区长度代替;

存储在缓冲区中的有效数据的开始位置(读指针);

存储在缓冲区中的有效数据的结尾位置(写指针)。

缓冲区是满、或是空,都有可能出现读指针与写指针指向同⼀位置:

缓冲区中总是有⼀个存储单元保持未使⽤状态。缓冲区最多存⼊(size-1)个数据。如果读写指针指向同⼀位置,则缓冲区为空。如果写指

针位于读指针的相邻后⼀个位置,则缓冲区为满。

2chan内部数据结构

2.1chan的数据结构

chan实质是个环形缓冲区,外加⼀个接受者协程队列和⼀个发送者协程队列

buf:环形缓冲区

sendx:⽤于记录buf这个循环链表中的发送的index

recvx:⽤于记录buf这个循环链表中接收的index

recvq:接受者协程队列

sendq:发送者协程队列

lock:互斥锁

2.2有缓冲区和⽆缓冲区chan的区别

2.2.1⽆缓冲chan数据同步过程和sudog结构

1.创建⼀个发送者列表和接收者列表都为空的channel。

2.第⼀个协程向channel发送变量的值

l从池中获取⼀个sudog结构体变量,⽤于表⽰发送者。sudog结构体会保持对发送者所在协程的引⽤,以及发送变量的引

⽤。

4.发送者加⼊sendq队列。

5.发送者协程进⼊等待状态。

6.第⼆个协程将从channel中读取⼀个消息

l将sendq列表中等待状态的发送者出队列。

使⽤memmove函数将发送者要发送的值进⾏拷贝,包装⼊sudog结构体,再传递给channel接收者的接收变量。

9.在第五步中被挂起的第⼀个协程将恢复运⾏并释放第三步中获取的sudog结构体。

2.2.1有缓冲chan

有缓冲chan实质是使⽤了完整的环形缓冲区,只要缓冲区有空闲,则发送者⽆需进⼊等待队列,直接将数据放⼊环形缓冲区中,如果缓冲

区有数据,接受者⽆需进⼊等待队列,直接从环形缓冲区中获取数据。

3关键源码分析

3.1chan数据结构源码

typehchanstruct{

qcountuint//totaldatainthequeue

dataqsizuint//sizeofthecircularqueue

r//pointstoanarrayofdataqsizelements

elemsizeuint16

closeduint32

elemtype*_type//elementtype

sendxuint//sendindex

recvxuint//receiveindex

recvqwaitq//listofrecvwaiters

sendqwaitq//listofsendwaiters

//lockprotectsallfieldsinhchan,aswellasseveral

//fieldsinsudogsblockedonthischannel.

//

//DonotchangeanotherG'sstatuswhileholdingthislock

//(inparticular,donotreadyaG),asthiscandeadlock

//withstackshrinking.

lockmutex

}

3.2sudog数据结构源码

//sudogrepresentsaginawaitlist,suchasforsending/receiving

//onachannel.

//

//sudogisnecessarybecausetheg↔synchronizationobjectrelation

//eonmanywaitlists,sotheremaybe

//manysudogsforoneg;andmanygsmaybewaitingonthesame

//synchronizationobject,sotheremaybemanysudogsforoneobject.

//

//uireSudogand

//releaseSudogtoallocateandfreethem.

typesudogstruct{

//the

//stackdependson

//thisforsudogsinvolvedinchannelops.

g*g

//isSelectindicatesgisparticipatinginaselect,so

//DonemustbeCAS'dtowinthewake-uprace.

isSelectbool

next*sudog

prev*sudog

r//dataelement(maypointtostack)

//Thefollowingfieldsareneveraccessedconcurrently.

//Forchannels,waitlinkisonlyaccessedbyg.

//Forsemaphores,allfields(includingtheonesabove)

//areonlyaccessedwhenholdingasemaRootlock.

acquiretimeint64

releasetimeint64

ticketuint32

parent*sudog//semaRootbinarytree

waitlink*sudog//glistorsemaRoot

waittail*sudog//semaRoot

c*hchan//channel

}

3.3chan的构造过程

funcmakechan(t*chantype,sizeint)*hchan{

elem:=

//compilerchecksthisbutbesafe.

>=1<<16{

throw("makechan:invalidchannelelementtype")

}

ifhchanSize%maxAlign!=0||>maxAlign{

throw("makechan:badalignment")

}

mem,overflow:=tptr(,uintptr(size))

ifoverflow||mem>maxAlloc-hchanSize||size<0{

panic(plainError("makechan:sizeoutofrange"))

}

//HchandoesnotcontainpointersinterestingforGCwhenelementsstoredinbufdonotcontainpointers.

//bufpointsintothesameallocation,elemtypeispersistent.

//SudoG'sarereferencedfromtheirowningthreadsotheycan'tbecollected.

//TODO(dvyukov,rlh):Rethinkwhencollectorcanmoveallocatedobjects.

varc*hchan

switch{

casemem==0:

//Queueorelementsizeiszero.

c=(*hchan)(mallocgc(hchanSize,nil,true))

//Racedetectorusesthislocationforsynchronization.

=dr()

a==0:

//Elementsdonotcontainpointers.

//Allocatehchanandbufinonecall.

c=(*hchan)(mallocgc(hchanSize+mem,nil,true))

=add(r(c),hchanSize)

default:

//Elementscontainpointers.

c=new(hchan)

=mallocgc(mem,elem,true)

}

ze=uint16()

pe=elem

iz=uint(size)

ifdebugChan{

print("makechan:chan=",c,";elemsize=",,";dataqsiz=",size,"n")

}

returnc

}

可以看到,如果不传⼊size或size=0,则没有为环形缓冲区分配内存,职位chan结构分配内存

3.4⽆缓冲收发

//Sendsandreceivesonunbufferedorempty-bufferedchannelsarethe

//onlyoperationswhereonerunninggoroutinewritestothestackof

//ssumesthatstackwritesonly

//happenwhenthegoroutineisrunningandareonlydonebythat

//writebarrierissufficienttomakeupfor

//violatingthatassumption,butthewritebarrierhastowork.

//typedmemmovewillcallbulkBarrierPreWrite,butthetargetbytes

//arenotintheheap,ngetocall

//memmoveandtypeBitsBulkBarrierinstead.

funcsendDirect(t*_type,sg*sudog,r){

//srcisonourstack,dstisaslotonanotherstack.

//tofsg,itwillnolonger

//beupdatedifthedestination'sstackgetscopied(shrunk).

//Somakesurethatnopreemptionpointscanhappenbetweenread&use.

dst:=

typeBitsBulkBarrier(t,uintptr(dst),uintptr(src),)

//Noneedforcgowritebarrierchecksbecausedstisalways

//Gomemory.

memmove(dst,src,)

}

funcrecvDirect(t*_type,sg*sudog,r){

//dstisonourstackortheheap,srcisonanotherstack.

//Thechannelislocked,sosrcwillnotmoveduringthis

//operation.

src:=

typeBitsBulkBarrier(t,uintptr(dst),uintptr(src),)

memmove(dst,src,)

}

参考:

更多推荐

queue_work