C language implementation of the co-process

Source: Internet
Author: User

These days suddenly interested in the association process, so that they achieved a, the code on GitHub: Https://github.com/adinosaur/Coro

The process is a non-preemptive thread of user space, which is mainly used to solve the problem of waiting for a large number of IO operations.

Co-process vs thread

Compared to the use of multithreading to solve the IO blocking task, the advantage of using the co-operation is not to lock, access to the shared data without synchronization. One thing to note here is that the use of the coprocessor does not require locking because all the processes are running in only one thread, but because of the non-preemptive nature of the process. In other words, if the use of the process, before the initiative to hand over the CPU will not be suddenly switched to other co-process. While threads are preemptive, using multithreading you are not sure when your thread is being dispatched by the operating system and when it is switched on, so you need to use locks to implement the semantics of an atomic operation.

Coprocessor vs Asynchronous Callbacks

In fact, it is more common to use non-blocking IO (such as asynchronous Io, or a set of asynchronous IO that is implemented on Syscall itself, such as ASIO) and write processing operations in the callback function. This is generally not a problem, but when the callback function becomes more, a coherent business code is split into multiple callback functions, increasing the cost of maintenance. Therefore, the use of the co-process can be used in a synchronous way to write the effect of the very asynchronous code.

Using static variables to implement a co-process

The main problem with implementing a process is how to save the context of a function call. Previously saw a blog on the Internet coroutines in C, a very concise way to implement the function of this save context. The implementation code is as follows:

1 #definecrbegin static int _cr_state = 0; Switch (_cr_state) {case 0:2 #defineCrreturn (x) do {_cr_state = __line__, return x; case __line__:;} while (0)3 #defineCrfinish}4 5 intfunc1 () {6 Crbegin7      while(1)8     {9printf"Hello world\n");TenCrreturn (0); One     } A Crfinish -}

This code takes advantage of the function's static variable to hold the function call state. Note that since vs2013 has a debug feature, the implementation of the vs2013 __line__ is not a constant and will not be compiled, so it can be compiled using GCC. This code is simple but problematic, for example, if two processes call the same function, an error occurs. So the blog mentions this code is mainly to give a train of thought, if the actual use of such a son is certainly not.

Using setjmp and longjmp to realize the co-process

As I said earlier, the main thing about implementing a process is to save the context of the call to the function, which is basically two parts: 1. The value of each register, 2. function Call stack. C language can be setjmp to save the function call, the value of each register. Once saved, the longjmp can be reproduced back to the original setjmp (can be understood as a cross function goto). However, it is important to note that SETJMP is only responsible for preserving the value of the register and is not responsible for maintaining its function call stack (a look at the structure of the setjmp jmp_buf), so the function call stack must be maintained manually by the consumer. A common mistake in using setjmp, longjmp, is to try to longjmp to a function that has been executed, while the value of the register is the value that was saved at the time, but the call stack is not the original call stack.

What I did was to request a block of space (2M size) on the heap as the call stack for the setjmp when creating a process, and then manually change the value of the Register ESP to point to the call stack I created myself. So at a later time, this process will use the memory I provided as a stack.

My co-Libraries provides three interfaces:

    1. Coro_new: Create a co-process
    2. Coro_yield: Returns control to the scheduling association
    3. Coro_main: Run Scheduling Association

The control flow of the co-process is as follows:

    1. Run the scheduling process through Coro_main and find the next run, run it.
    2. Run this process until it calls Coro_yield to return control to the scheduling association.
    3. Repeat the above two steps until all the threads have finished running.

This libraries implementation is very simple, only the 100来 line of code, of course, to achieve its purpose is to provide a simplest model of the co-operation, rather than a full-featured, robust and strong to put into the actual business of the process.

So there are a lot of questions:

    1. For example, when the call stack in the process of more than 2M, this is to be processed, the current code is not done, it should be interrupted program, avoid writing bad heap, produce random non-reproducible problems.
    2. Obviously when implemented without taking into account multi-threading, if running in a multithreaded environment, the code needs to do synchronous processing.
    3. Now this version of the association has a convention, the function called in the Association can not block the syscall, which is obviously unscientific. A complete co-libraries should contain some commonly used syscall implementations of non-blocking, after all only one thread cannot really block on this call.
    4. The JMP_BUF implementations of different platforms may not be consistent, so you need to rewrite the code slightly on other platforms.

Summarize

Of course, there are some better ways to implement the process, such as if you can use the GLIBC Ucontext Library can be based on this library to implement, rather than manually manage the context of function calls, such as the implementation of cloud wind libraries.

Resources

    1. Coroutines in C. Address: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
    2. cerl++. Address: Https://zhuanlan.zhihu.com/p/19945225?refer=impress-your-cat
    3. C's Coroutine library. Address: http://blog.codingnow.com/2012/07/c_coroutine.html
cerl++

C language implementation of the co-process

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.