{{htmlmetatags>metatag-robots=() metatag-title=(Coordinate the protothreads | Multithreading on retrocomputers) metatag-keywords=(Multithreading,Commodore 64,Commodore VIC20,Atari,Commodore128,MIDRES Library,6502,6510) metatag-description=(How to implement fast and efficient multithreading on computers with limited resources.) metatag-media-og:image=(:mt6502.png) metatag-og:title=(Coordinate the protothreads | Multithreading on retrocomputers) metatag-og:description=(How to implement fast and efficient multithreading on computers with limited resources.) }} ====== Multithreading on retrocomputers ====== ===== BLOCKING AND NON-BLOCKING FUNCTIONS ===== A protothread runs inside a single C function and cannot "span" on other functions. It can, of course, call normal C functions but, at the same time, it cannot block inside a called function. This code, therefore, will never be able to run or compile correctly: void f( ) { ... MR_PTI_YIELD(); ... } MR_PT_THREAD(g) { ... f(); ... } This is because protothread ''g()'' will try to block execution when it is in function ''f()'', which itself is not a protothread. To overcome this limit, **a separate protothread can be generated for each potentially blocking function** and, consequently, a variable ''mr_protothread'' is allocated for it. MR_PT_THREAD(f) { ... MR_PTI_YIELD(); ... } mr_protothread fThread; MR_PT_THREAD(g) { ... MR_PTI_SPAWN(&fThread, f(&fThread)); ... } The advantage of this approach is that the blocking is explicit, and therefore **the programmer knows exactly which functions can block** and which ones they cannot block, thus simplifying debugging by simply reading the code. Move to [[:mt6502:locals|HOW TO MANAGE LOCAL VARIABLES]].