Preface
In the fields of industrial automation and machine vision, the requirements for real-time, reliability and efficiency are increasingly high. To meet these needs, we have developed a C# concurrent process control framework designed for industrial automation motion control and machine vision process development.
This framework is not only suitable for various industrial automation scenarios, but also can achieve more than one million scheduling frequencies per second in a single-threaded environment, so as to calmly deal with complex tasks involving thousands of input and output points.
Concurrent process control framework
This framework provides a new concurrency process control framework that draws on efficient concurrency patterns in the Golang language and performs necessary functional extensions on this basis. The framework not only supports custom single/multi-threaded scheduling mechanisms, but also allows scheduling in the main UI thread, thus simplifying the interaction between logic and user interface.
In addition, the framework also integrates high-precision timers, configurable scheduling priorities, logical stops and pauses, allowing us to more flexibly manage and control complex automation processes.
Framework Advantages
- Compared with traditional models: Compared with traditional multi-threaded models, state machine models and PLC-like models, this framework has a more compact and clear logical structure, which significantly improves development efficiency and simplifies subsequent maintenance and upgrade processes.
- Inspired by Go: The design of the framework borrows the efficient concurrency model in Go, and on this basis, it has carried out necessary functional extensions to meet the specific needs of the industrial automation field.
- Flexible scheduling mechanism: supports custom single-thread or multi-thread scheduling, and can also be scheduled in the main UI thread, which facilitates the interaction between logic and user interface and enhances the user experience.
- Rich built-in functions: built-in high-precision timer, configurable scheduling priority, logical stop and logical pause functions to ensure the accuracy and controllability of task execution.
- Tree multi-task scheduling: The tree structure is used to manage multi-task scheduling, which improves the reliability of the logic and the overall stability of the system.
- Excellent performance: In a single-threaded environment, it can achieve more than one million scheduling frequencies per second, and can calmly deal with complex scenarios of thousands of input and output points.
- Extensive practice verification: The framework has been successfully applied in multiple practical projects, demonstrating its stability and reliability.
Framework example
A series of different task execution patterns are defined in the code, showing how to manage concurrent tasks through different scheduling strategies.
- Global variables
static shared_strand strand: a globally shared scheduler used to ensure thread safety.
- Logging function
Log(string msg): Records log information with timestamps to the console.
- Work task functions
Worker(string name, int time = 1000): Simulates a simple task that prints a message after the specified number of milliseconds.
- Main function
MainWorker(): Asynchronous main task function, calling the various task modes defined above in turn.
Main(string[] args): The program entry point, initializes the work service, share scheduler, and starts the main task.
using System; using ; using ; using ; using ; using Go; namespace WorkerFlow { class Program { static shared_strand strand; static void Log(string msg) { ($"{("HH:mm:")} {msg}"); } static async Task Worker(string name, int time = 1000) { await (time); Log(name); } //1 A, B, C are serially serially //A->B->C static async Task Worker1() { await Worker("A"); await Worker("B"); await Worker("C"); } //2 A, B, and C are all in parallel and rely on the same strand (implicit parameters, all tasks that rely on the same strand are thread-safe) //A //B //C static async Task Worker2() { children = new (); (() => Worker("A")); (() => Worker("B")); (() => Worker("C")); await children.wait_all(); } //3 After A is executed, B and C will be in parallel // -->B // | //A-> // | // -->C static async Task Worker3() { await Worker("A"); children = new (); (() => Worker("B")); (() => Worker("C")); await children.wait_all(); } //4 After B and C are executed in parallel, execute A //B-- // | // -->A // | //C-- static async Task Worker4() { children = new (); (() => Worker("B")); (() => Worker("C")); await children.wait_all(); await Worker("A"); } //5 After any B and C are executed, then execute A //B-- // | // >-->A // | //C-- static async Task Worker5() { children = new (); var B = (() => Worker("B", 1000)); var C = (() => Worker("C", 2000)); var task = await children.wait_any(); if (task == B) { Log("B success"); } else { Log("C Success"); } await Worker("A"); } //6 Waiting for a specific task static async Task Worker6() { children = new (); var A = (() => Worker("A")); var B = (() => Worker("B")); await (A); } //7 Timeout waiting for a specific task, and then abort all tasks static async Task Worker7() { children = new (); var A = (() => Worker("A", 1000)); var B = (() => Worker("B", 2000)); if (await children.timed_wait(1500, A)) { Log("success"); } else { Log("time out"); } await (); } //8 Timeout waiting for a set of tasks, and then abort all tasks static async Task Worker8() { children = new (); (() => Worker("A", 1000)); (() => Worker("B", 2000)); var tasks = await children.timed_wait_all(1500); await (); Log($"success{}indivual"); } //9 Wait for a set of tasks over time, then abort all tasks, and handle them on-site during the abort task static async Task Worker9() { children = new (); (() => Worker("A", 1000)); (async delegate () { try { await Worker("B", 2000); } catch (generator.stop_exception) { Log("B was aborted"); await (500); throw; } catch () { } }); var task = await children.timed_wait_all(1500); await (); Log($"success{}indivual"); } //10 Nested tasks static async Task Worker10() { children = new (); (async delegate () { children1 = new (); (() => Worker("A")); (() => Worker("B")); await children1.wait_all(); }); (async delegate () { children1 = new (); (() => Worker("C")); (() => Worker("D")); await children1.wait_all(); }); await children.wait_all(); } //11 Nesting abort static async Task Worker11() { children = new (); (() => Worker("A", 1000)); (async delegate () { try { children1 = new (); (async delegate () { try { await Worker("B", 2000); } catch (generator.stop_exception) { Log("B is aborted 1"); await (500); throw; } catch () { } }); await children1.wait_all(); } catch (generator.stop_exception) { Log("B was aborted 2"); throw; } catch () { } }); await (1500); await (); } //12 Perform in parallel and wait for a set of time-consuming algorithms static async Task Worker12() { wait_group wg = new wait_group(); for (int i = 0; i < 2; i++) { (); int idx = i; var _ = (delegate () { try { Log($"Execution algorithm{idx}"); } finally { (); } }); } await (); Log("Execution algorithm completed"); } //13 Serial execution time-consuming algorithm, the time-consuming algorithm must be executed in the thread pool, otherwise the scheduling that depends on the same strand will not be timely static async Task Worker13() { for (int i = 0; i < 2; i++) { await generator.send_task(() => Log($"Execution algorithm{i}")); } } static async Task MainWorker() { await Worker1(); await Worker2(); await Worker3(); await Worker4(); await Worker5(); await Worker6(); await Worker7(); await Worker8(); await Worker9(); await Worker10(); await Worker11(); await Worker12(); await Worker13(); } static void Main(string[] args) { work_service work = new work_service(); strand = new work_strand(work); (strand, MainWorker); (); (); } } }
Frame address
- Gitee: /hamasm/CsGo
Summarize
It is worth mentioning that this framework is specially designed for industrial automation motion control and machine vision process development. Its unique tree multi-task scheduling mechanism greatly improves the reliability of logic. At the same time, the number of scheduling times per second in a single-threaded environment can reach more than one million times, which is enough to cope with application scenarios involving thousands of input and output points. After practical verification by multiple projects, its stability and reliability have been proven, providing strong support for industrial automation.
Through the introduction of this article, we hope to provide developers in the field of industrial automation with an efficient, reliable and easy-to-use tool. With this tool, people can more easily deal with the challenges of concurrent processing when building complex control systems. We also look forward to leaving a message in the comment area to share your valuable experience and suggestions.
This is the article about the C# concurrency control framework that implements millions of scheduling per second in a single-threaded environment. For more related C# millions of scheduling per second, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!