{"id":17321930,"url":"https://github.com/petercorke/simple-threads-coder","last_synced_at":"2025-04-14T16:10:17.794Z","repository":{"id":93428590,"uuid":"146297597","full_name":"petercorke/simple-threads-coder","owner":"petercorke","description":"A simple POSIX threading library for MATLAB Coder","archived":false,"fork":false,"pushed_at":"2018-09-17T01:15:27.000Z","size":2278,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-22T19:36:44.755Z","etag":null,"topics":["codegen","matlab","matlab-coder","mutexes","posix","semaphores","threads","web-server","web-services-restful"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/petercorke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-27T12:56:55.000Z","updated_at":"2024-01-10T13:28:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"479231c9-7e27-4cfc-9549-cd98af356f3c","html_url":"https://github.com/petercorke/simple-threads-coder","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petercorke%2Fsimple-threads-coder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petercorke%2Fsimple-threads-coder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petercorke%2Fsimple-threads-coder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petercorke%2Fsimple-threads-coder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/petercorke","download_url":"https://codeload.github.com/petercorke/simple-threads-coder/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240713056,"owners_count":19845589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codegen","matlab","matlab-coder","mutexes","posix","semaphores","threads","web-server","web-services-restful"],"created_at":"2024-10-15T13:40:21.499Z","updated_at":"2025-02-25T17:30:52.787Z","avatar_url":"https://github.com/petercorke.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simple thread library (STL) for MATLAB Coder\n\nCopyright \u0026copy; 2018 Peter Corke\n\nSTL provides POSIX thread primitives to MATLAB\u0026reg; code that has been converted to C code using the MATLAB Coder\u0026reg; toolchain.  It allows multi-threaded operation on Linux and MacOS platforms (I don't have access to Windows to test).\n\nSTL provides threads, semaphores, mutexes, high resolution delay, timers (Linux only), logging and an embedded web server that supports templating.\n\nTo use this you must have a licence for MATLAB\u0026reg; and MATLAB Coder\u0026reg;.\n\nMore details in the [project Wiki](https://github.com/petercorke/simple-threads-coder/wiki).\n\nAlso listed in [MATLAB File Exchange](https://www.mathworks.com/matlabcentral/fileexchange/68648-simple-threads-coder).\n\n## Collaborate\n\nIf you download and test this, please send me your feedback.  If you're interested in helping with development, even better, please contact me and we can make a plan.  A non-exhaustive list of short- and long-term development topics is on the [Wiki](https://github.com/petercorke/simple-threads-coder/wiki).\n\n\n## Example 1: Threading\n\nConsider this example with one main function and three additional threads.  You can find this in `examples/threads`.\n\n`user.m`\n```matlab\nfunction user  %#codegen\n    % we can print to stderr\n    fprintf(2, 'hello world\\n');\n    \n    % we have access to command line arguments\n    fprintf(2, 'got %d arguments\\n', argc() );\n    for i=0:argc()-1\n        fprintf(2, ' arg %d: %s\\n', i, argv(i));\n    end\n    \n    % we can send timestamped messages to the log\n    %  - no need to put a new line on the end\n    stllog('hello world');\n    \n    % note that if we send a string argument we need to convert it to a\n    % C string\n    stllog('%s', cstring('hello world'));\n\n    % now we can launch a couple of threads, see thread1.m and thread2.m\n    %  launching returns a thread id, a small integer\n    t1 = launch('thread1')\n    stllog('thread id %d', t1)\n    t2 = launch('thread2')\n    stllog('thread id %d', t2)\n    \n    join(t1);  % wait for thread 1 to finish\n    sleep(5);\n    cancel(t2); % kill thread 2 and wait for it\n    join(t2)\n    \n    sleep(2)\n    \n    % create a semaphore\n    s1 = newsemaphore('sem1');\n    stllog('sem id %d', s1);\n    sleep(1)\n    \n    % launch a new thread, see thread3.m\n    %  it just waits for the semaphore, then prints a message\n    t3 = launch('thread3');\n    stllog('thread id %d', t3);\n    \n    sleep(2);\n    sempost(0);  % wake up thread 3\n    sleep(1);\n    sempost(0);  % wake up thread 3\n    sleep(2);\n    \n    % done, exiting will tear down all the threads\nend\n```\n\n`thread1.m`\n```matlab\nfunction thread1() %#codegen\n    for i=1:10\n        stllog('hello from thread1, id #%d', self());\n        sleep(1)\n    end\nend\n```\n\n`thread2.m`\n```matlab\nfunction thread2() %#codegen\n    for i=1:20\n        stllog('hello from thread2, id #%d', self());\n        sleep(2)\n    end\nend\n```\n\n`thread3.m`\n```matlab\nfunction thread3() %#codegen\n    while true\n        semwait(0);\n        stllog('hello from thread 3');\n    end\nend\n```\n\n### Building and running the application\n\n```matlab\n\u003e\u003e make\n```\n\nThe key parts of this file is the last line\n\n```matlab\ncodegen user.m thread1.m thread2.m thread3.m  -config cfg\n```\nThere are four files provided to `codegen`.  The first is the user's \"main\" function -- the file `user.m` -- which is executed when the executable is run.  Then we list the three additional threads.\n\nThe earlier lines in `make.m` simply configure the build process which is captured in the state of the `coder.config` object `cfg` which is passed as the last argument to `codegen`.\n\nEnsure that the folder `stl` is in your MATLAB path.\n\nThe result is an executable `user` in the current directory which we can run\n```\n% ./user bob alice\nhello world\ngot 3 arguments\n arg 0: ./user\n arg 1: bob\n arg 2: alice\n2018-09-16 16:52:38.281053 [user] hello world\n2018-09-16 16:52:38.281793 [user] hello world\n2018-09-16 16:52:38.281841 [user] thread id 1\n2018-09-16 16:52:38.281850 [thread1] starting posix thread \u003cthread1\u003e (0xFCD5A10) \n2018-09-16 16:52:38.281860 [user] thread id 2\n2018-09-16 16:52:38.281869 [thread2] starting posix thread \u003cthread2\u003e (0xFCD5B10) \n2018-09-16 16:52:38.281876 [user] waiting for thread #1 \u003cthread1\u003e\n2018-09-16 16:52:38.281914 [thread1] hello from thread1\n2018-09-16 16:52:38.281927 [thread2] hello from thread2, id #2\n2018-09-16 16:52:38.281963 [thread1] hello from thread1, id #1\n2018-09-16 16:52:39.286172 [thread1] hello from thread1, id #1\n2018-09-16 16:52:40.285643 [thread2] hello from thread2, id #2\n2018-09-16 16:52:40.286787 [thread1] hello from thread1, id #1\n2018-09-16 16:52:41.286863 [thread1] hello from thread1, id #1\n2018-09-16 16:52:42.286156 [thread2] hello from thread2, id #2\n2018-09-16 16:52:42.287227 [thread1] hello from thread1, id #1\n2018-09-16 16:52:43.287423 [thread1] hello from thread1, id #1\n2018-09-16 16:52:44.289092 [thread1] hello from thread1, id #1\n2018-09-16 16:52:44.289092 [thread2] hello from thread2, id #2\n2018-09-16 16:52:45.289178 [thread1] hello from thread1, id #1\n2018-09-16 16:52:46.292749 [thread1] hello from thread1, id #1\n2018-09-16 16:52:46.292746 [thread2] hello from thread2, id #2\n2018-09-16 16:52:47.297975 [thread1] hello from thread1, id #1\n2018-09-16 16:52:48.297823 [thread2] hello from thread2, id #2\n2018-09-16 16:52:48.299590 [thread1] MATLAB function \u003cthread1\u003e has returned, thread exiting\n2018-09-16 16:52:48.299666 [user] thread complete #1 \u003cthread1\u003e\n2018-09-16 16:52:50.302948 [thread2] hello from thread2, id #2\n2018-09-16 16:52:52.307330 [thread2] hello from thread2, id #2\n2018-09-16 16:52:53.301583 [user] cancelling thread #2 \u003cthread2\u003e\n2018-09-16 16:52:53.301710 [user] waiting for thread #2 \u003cthread2\u003e\n2018-09-16 16:52:53.301815 [user] thread complete #2 \u003cthread2\u003e\n2018-09-16 16:52:55.302909 [user] creating semaphore #0 \u003csem1\u003e\n2018-09-16 16:52:55.302950 [user] sem id 0\n2018-09-16 16:52:56.307164 [user] thread id 1\n2018-09-16 16:52:56.307204 [thread3] starting posix thread \u003cthread3\u003e (0xFCD5BD0) \n2018-09-16 16:52:56.307233 [thread3] waiting for semaphore #0 \u003csem1\u003e\n2018-09-16 16:52:58.311708 [user] posting semaphore #0 \u003csem1\u003e\n2018-09-16 16:52:58.311830 [thread3] semaphore wait complete #0\n2018-09-16 16:52:58.311845 [thread3] hello from thread 3\n2018-09-16 16:52:58.311855 [thread3] waiting for semaphore #0 \u003csem1\u003e\n2018-09-16 16:52:59.312160 [user] posting semaphore #0 \u003csem1\u003e\n2018-09-16 16:52:59.312197 [thread3] semaphore wait complete #0\n2018-09-16 16:52:59.312204 [thread3] hello from thread 3\n2018-09-16 16:52:59.312208 [thread3] waiting for semaphore #0 \u003csem1\u003e\n```\n\n## Example 2: Web server\nThe user's main program is quite simple:\n```matlab\nfunction user() %#codegen\n    stl.log('user program starts');\n    webserver(8080, 'myserver');\n    stl.sleep(60);\nend\n```\n\nPointing a browser at port 8080 on the host running the program interacts with the MATLAB webserver code which is fairly clearly expressed.\n```matlab\nfunction myserver()   % called on every page request\n    switch (webserver.url())\n        case '/'\n            stl.log('in /')\n            webserver.html('home here');\n        case '/page1'\n            stl.log('in /page1');\n            if webserver.isGET()\n                stl.log('GET request');\n            end\n            a = webserver.getarg('a');\n            if ~isempty(a)\n                stl.log('a = %s', cstring(a));\n            end\n            webserver.html('\u003chtml\u003e\u003cbody\u003ehello \u003cb\u003efrom\u003c/b\u003e /page1\u003c/body\u003e\u003c/html\u003e');\n        case '/page2'\n            stl.log('in /page2')\n            vals.a = 1;\n            vals.b = 2;\n            webserver.template('templates/page2.html', vals);\n        case '/duck'\n            webserver.file('duck.jpg', 'image/jpeg');\n        case '/input'\n            if webserver.isPOST()\n                stl.log('POST request');\n                foo = webserver.postarg('Foo');\n                stl.log('foo = %s', cstring(foo));\n            else\n                stl.log('GET request');\n            end\n            webserver.template('templates/input.html');\n    end\nend\n```\nThe switch statement is used to select the code according to the URL given, and other methods provide access to parameters of the HTTP request.\n\u003chr /\u003e\n\n![page1](https://github.com/petercorke/simple-threads-coder/blob/master/doc/page1.png)\n\n```\n2018-09-16 15:54:28.635937 [user] user program starts\n2018-09-16 15:54:28.636843 [user] web server starting on port 8080\n2018-09-16 15:54:33.170370 [user] web: GET request using HTTP/1.1 for URL /page1 \n2018-09-16 15:54:33.170410 [WEB] in /page1\n2018-09-16 15:54:33.170416 [WEB] GET request\n2018-09-16 15:54:33.170421 [WEB] a = 7\n2018-09-16 15:54:33.170425 [WEB] web_html: \u003chtml\u003e\u003cbody\u003ehello \u003cb\u003efrom\u003c/b\u003e /page1\u003c/body\u003e\u003c/html\u003e\u003c/body\u003e\u003c/html\u003e\n```\nNote the arguements `?a=7\u0026b=12` on the end of the URL. These are GET arguments of the form `key=value`, and the method `getarg` provides access to them by key.  In this case we get the value of the key `a`.\n\nNote also, that log messages from the web server function are listed as coming from the `WEB` thread, which is created by `webserver()`.\n\u003chr /\u003e\n\n![page2](https://github.com/petercorke/simple-threads-coder/blob/master/doc/page2.png)\n\n```\n2018-09-16 15:39:12.816790 [WEB] web: GET request using HTTP/1.1 for URL /page2 \n2018-09-16 15:39:12.816822 [WEB] in /page2\n2018-09-16 15:39:12.816827 [WEB] web_setvalue: a 1\n2018-09-16 15:39:12.816849 [WEB] web_setvalue: b 2\n2018-09-16 15:39:12.816854 [WEB] web_template: templates/page2.html\n```\n\nThe template file is sent to the browser with substitutions.  The  `page2.html` looks like\n```html\n\u003chtml\u003e\n\u003cbody\u003e\n\u003cp\u003eThis is a test page\u003c/p\u003e\n\u003cp\u003ea = \u003cTMPL_VAR name=\"a\"\u003e\u003c/p\u003e\n\u003cp\u003eb = \u003cTMPL_VAR name=\"b\"\u003e\u003c/p\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\nand the values of the fields of the struct `vals` are substituted for the corresonding named `TMPL_VAR` tags.\n\u003chr /\u003e\n\n![duck](https://github.com/petercorke/simple-threads-coder/blob/master/doc/duck.png)\n\n```\n2018-09-16 15:36:08.881139 [WEB] web: GET request using HTTP/1.1 for URL /duck \n2018-09-16 15:36:08.881159 [WEB] web_file: duck.jpg, type image/jpeg\n2018-09-16 15:36:08.881208 [WEB] file is 83234 bytes\n```\nThe local file `duck.png` is sent to the browser as an `image/jpeg` filetype.\n\u003chr /\u003e\n\n![post](https://github.com/petercorke/simple-threads-coder/blob/master/doc/post.png)\n\n```\n2018-09-16 16:32:00.035029 [user] web: GET request using HTTP/1.1 for URL /input \n2018-09-16 16:32:00.035101 [WEB] input called\n2018-09-16 16:32:00.035109 [WEB] GET request\n2018-09-16 16:32:00.035118 [WEB] web_template: templates/input.html\n2018-09-16 16:32:04.385387 [WEB] web: POST request using HTTP/1.1 for URL /input \n2018-09-16 16:32:04.385580 [WEB] web: POST request using HTTP/1.1 for URL /input \n2018-09-16 16:32:04.385623 [WEB] POST [Foo] = 27\n2018-09-16 16:32:04.385634 [WEB] POST [button] = Button2\n2018-09-16 16:32:04.385655 [WEB] web: POST request using HTTP/1.1 for URL /input \n2018-09-16 16:32:04.385666 [WEB] input called\n2018-09-16 16:32:04.385671 [WEB] POST request\n2018-09-16 16:32:04.385676 [WEB] foo = 27\n2018-09-16 16:32:04.385681 [WEB] web_template: templates/input.html\n```\nThis example is rather more complex.  The page is requested with a standard GET request and the HTML file `input.html` is returned to the browser\n```html\n\u003chtml\u003e\n\u003cbody\u003e\n\u003cp\u003eThis is a page to test POST\u003c/p\u003e\n  \u003cform action=\"\" method=\"post\"\u003e\n     \u003cp\u003eEnter value of foo:\n     \u003c!-- POST key = Foo, POST value is entered tect --\u003e\n     \u003cinput type=\"text\" value=\"0\" name=\"Foo\" /\u003e\n\n     \u003c!-- button label is given by value, POST key = button, POST value = Button1/2 --\u003e\n     \u003cp\u003e\u003cinput type=\"submit\" value=\"Button1\" name=\"button\" /\u003e\u003c/p\u003e\n     \u003cp\u003e\u003cinput type=\"submit\" value=\"Button2\" name=\"button\" /\u003e\u003c/p\u003e\n  \u003c/form\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n  The browser displays a form with a text input box and two buttons.  When either button (or a newline) is entered, the browser sends the contents of the text box and the button that pushed as `name=value` pairs.  The postarg method gets the value of the textbox which has `name=Foo`. The diagnostic messages show that `Button2` was pressed, and this could be tested by accessing the value for the name `button`.\n\n  The POST request must return a value, and in this case it is template file.\n\n---\nCreated using Sublime3 with awesome packages `MarkdownEditing`, `MarkdownPreview` and `Livereload` for WYSIWYG markdown editing. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercorke%2Fsimple-threads-coder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetercorke%2Fsimple-threads-coder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercorke%2Fsimple-threads-coder/lists"}