An open API service indexing awesome lists of open source software.

https://github.com/petercorke/simple-threads-coder

A simple POSIX threading library for MATLAB Coder
https://github.com/petercorke/simple-threads-coder

codegen matlab matlab-coder mutexes posix semaphores threads web-server web-services-restful

Last synced: 14 days ago
JSON representation

A simple POSIX threading library for MATLAB Coder

Awesome Lists containing this project

README

        

# Simple thread library (STL) for MATLAB Coder

Copyright © 2018 Peter Corke

STL provides POSIX thread primitives to MATLAB® code that has been converted to C code using the MATLAB Coder® toolchain. It allows multi-threaded operation on Linux and MacOS platforms (I don't have access to Windows to test).

STL provides threads, semaphores, mutexes, high resolution delay, timers (Linux only), logging and an embedded web server that supports templating.

To use this you must have a licence for MATLAB® and MATLAB Coder®.

More details in the [project Wiki](https://github.com/petercorke/simple-threads-coder/wiki).

Also listed in [MATLAB File Exchange](https://www.mathworks.com/matlabcentral/fileexchange/68648-simple-threads-coder).

## Collaborate

If 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).

## Example 1: Threading

Consider this example with one main function and three additional threads. You can find this in `examples/threads`.

`user.m`
```matlab
function user %#codegen
% we can print to stderr
fprintf(2, 'hello world\n');

% we have access to command line arguments
fprintf(2, 'got %d arguments\n', argc() );
for i=0:argc()-1
fprintf(2, ' arg %d: %s\n', i, argv(i));
end

% we can send timestamped messages to the log
% - no need to put a new line on the end
stllog('hello world');

% note that if we send a string argument we need to convert it to a
% C string
stllog('%s', cstring('hello world'));

% now we can launch a couple of threads, see thread1.m and thread2.m
% launching returns a thread id, a small integer
t1 = launch('thread1')
stllog('thread id %d', t1)
t2 = launch('thread2')
stllog('thread id %d', t2)

join(t1); % wait for thread 1 to finish
sleep(5);
cancel(t2); % kill thread 2 and wait for it
join(t2)

sleep(2)

% create a semaphore
s1 = newsemaphore('sem1');
stllog('sem id %d', s1);
sleep(1)

% launch a new thread, see thread3.m
% it just waits for the semaphore, then prints a message
t3 = launch('thread3');
stllog('thread id %d', t3);

sleep(2);
sempost(0); % wake up thread 3
sleep(1);
sempost(0); % wake up thread 3
sleep(2);

% done, exiting will tear down all the threads
end
```

`thread1.m`
```matlab
function thread1() %#codegen
for i=1:10
stllog('hello from thread1, id #%d', self());
sleep(1)
end
end
```

`thread2.m`
```matlab
function thread2() %#codegen
for i=1:20
stllog('hello from thread2, id #%d', self());
sleep(2)
end
end
```

`thread3.m`
```matlab
function thread3() %#codegen
while true
semwait(0);
stllog('hello from thread 3');
end
end
```

### Building and running the application

```matlab
>> make
```

The key parts of this file is the last line

```matlab
codegen user.m thread1.m thread2.m thread3.m -config cfg
```
There 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.

The 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`.

Ensure that the folder `stl` is in your MATLAB path.

The result is an executable `user` in the current directory which we can run
```
% ./user bob alice
hello world
got 3 arguments
arg 0: ./user
arg 1: bob
arg 2: alice
2018-09-16 16:52:38.281053 [user] hello world
2018-09-16 16:52:38.281793 [user] hello world
2018-09-16 16:52:38.281841 [user] thread id 1
2018-09-16 16:52:38.281850 [thread1] starting posix thread (0xFCD5A10)
2018-09-16 16:52:38.281860 [user] thread id 2
2018-09-16 16:52:38.281869 [thread2] starting posix thread (0xFCD5B10)
2018-09-16 16:52:38.281876 [user] waiting for thread #1
2018-09-16 16:52:38.281914 [thread1] hello from thread1
2018-09-16 16:52:38.281927 [thread2] hello from thread2, id #2
2018-09-16 16:52:38.281963 [thread1] hello from thread1, id #1
2018-09-16 16:52:39.286172 [thread1] hello from thread1, id #1
2018-09-16 16:52:40.285643 [thread2] hello from thread2, id #2
2018-09-16 16:52:40.286787 [thread1] hello from thread1, id #1
2018-09-16 16:52:41.286863 [thread1] hello from thread1, id #1
2018-09-16 16:52:42.286156 [thread2] hello from thread2, id #2
2018-09-16 16:52:42.287227 [thread1] hello from thread1, id #1
2018-09-16 16:52:43.287423 [thread1] hello from thread1, id #1
2018-09-16 16:52:44.289092 [thread1] hello from thread1, id #1
2018-09-16 16:52:44.289092 [thread2] hello from thread2, id #2
2018-09-16 16:52:45.289178 [thread1] hello from thread1, id #1
2018-09-16 16:52:46.292749 [thread1] hello from thread1, id #1
2018-09-16 16:52:46.292746 [thread2] hello from thread2, id #2
2018-09-16 16:52:47.297975 [thread1] hello from thread1, id #1
2018-09-16 16:52:48.297823 [thread2] hello from thread2, id #2
2018-09-16 16:52:48.299590 [thread1] MATLAB function has returned, thread exiting
2018-09-16 16:52:48.299666 [user] thread complete #1
2018-09-16 16:52:50.302948 [thread2] hello from thread2, id #2
2018-09-16 16:52:52.307330 [thread2] hello from thread2, id #2
2018-09-16 16:52:53.301583 [user] cancelling thread #2
2018-09-16 16:52:53.301710 [user] waiting for thread #2
2018-09-16 16:52:53.301815 [user] thread complete #2
2018-09-16 16:52:55.302909 [user] creating semaphore #0
2018-09-16 16:52:55.302950 [user] sem id 0
2018-09-16 16:52:56.307164 [user] thread id 1
2018-09-16 16:52:56.307204 [thread3] starting posix thread (0xFCD5BD0)
2018-09-16 16:52:56.307233 [thread3] waiting for semaphore #0
2018-09-16 16:52:58.311708 [user] posting semaphore #0
2018-09-16 16:52:58.311830 [thread3] semaphore wait complete #0
2018-09-16 16:52:58.311845 [thread3] hello from thread 3
2018-09-16 16:52:58.311855 [thread3] waiting for semaphore #0
2018-09-16 16:52:59.312160 [user] posting semaphore #0
2018-09-16 16:52:59.312197 [thread3] semaphore wait complete #0
2018-09-16 16:52:59.312204 [thread3] hello from thread 3
2018-09-16 16:52:59.312208 [thread3] waiting for semaphore #0
```

## Example 2: Web server
The user's main program is quite simple:
```matlab
function user() %#codegen
stl.log('user program starts');
webserver(8080, 'myserver');
stl.sleep(60);
end
```

Pointing a browser at port 8080 on the host running the program interacts with the MATLAB webserver code which is fairly clearly expressed.
```matlab
function myserver() % called on every page request
switch (webserver.url())
case '/'
stl.log('in /')
webserver.html('home here');
case '/page1'
stl.log('in /page1');
if webserver.isGET()
stl.log('GET request');
end
a = webserver.getarg('a');
if ~isempty(a)
stl.log('a = %s', cstring(a));
end
webserver.html('hello from /page1');
case '/page2'
stl.log('in /page2')
vals.a = 1;
vals.b = 2;
webserver.template('templates/page2.html', vals);
case '/duck'
webserver.file('duck.jpg', 'image/jpeg');
case '/input'
if webserver.isPOST()
stl.log('POST request');
foo = webserver.postarg('Foo');
stl.log('foo = %s', cstring(foo));
else
stl.log('GET request');
end
webserver.template('templates/input.html');
end
end
```
The switch statement is used to select the code according to the URL given, and other methods provide access to parameters of the HTTP request.


![page1](https://github.com/petercorke/simple-threads-coder/blob/master/doc/page1.png)

```
2018-09-16 15:54:28.635937 [user] user program starts
2018-09-16 15:54:28.636843 [user] web server starting on port 8080
2018-09-16 15:54:33.170370 [user] web: GET request using HTTP/1.1 for URL /page1
2018-09-16 15:54:33.170410 [WEB] in /page1
2018-09-16 15:54:33.170416 [WEB] GET request
2018-09-16 15:54:33.170421 [WEB] a = 7
2018-09-16 15:54:33.170425 [WEB] web_html: hello from /page1

This is a test page


a =


b =

This is a page to test POST



Enter value of foo: