-
Notifications
You must be signed in to change notification settings - Fork 1
POSIX API
MATLAB function | Purpose | POSIX reference |
---|---|---|
argc | Get number of command line arguments | |
argv | Get command line argument | |
stllog | Print to log | |
launch | Create a thread | pthread_create |
cancel | Cancel a thread | pthread_cancel |
join | Wait for thread to complete | pthread_join |
semnew | Create semaphore | sem_create |
sempost | Post semaphore | sem_post |
semwait | Wait for semaphore | sem_wait |
mutex | Create a mutex | pthread_mutex_create |
mutlock | Lock a mutex | pthread_mutex_lock |
mutunlock | Unlock a mutex | pthread_mutex_unlock |
timer | Periodically set semaphore | timer_create |
Each operation is defined by a short file stl/*.m
which essentially wraps a function defined by stl.c
which is called using coder.ceval
.
Each additional thread must be defined in a separate m-file. This is a limitation of MATLAB Coder – each thread has to be in a separate file (an "entry point function").
If the function returns then the thread is terminated. Typically a thread would be a loop, perhaps even an infinite loop. The loop must contain some blocking operation such as waiting for:
- a semaphore or mutex
- a read or write transaction to some device (serial port, I2C etc.)
- a Linux system call.
This is not a cooperative threading environment, threads that do busy/wait polling will be preempted by the scheduler |
---|
When a thread is launched we can pass a uint32 to the thread function. To do this we need to declare a uint32
argument to codegen
using
codegen ... thread.m -args uint32(0) ...
Semaphores are used to allow threads to block or enable other threads. For the specific case of protecting a shared resource use a mutex.
id = semaphore(name)
returns the id of a new semaphore, initially not raised.
semwait(id)
blocks the thread until the semaphore is raised.
semwait(id,true)
tests if the semaphore is raised without blocking. If the semaphore is raised it returns true
and takes the semaphore, otherwise it returns false
.
sempost(id)
the semaphore is raised and all threads which are waiting on the semaphore are awakened.
Mutexes are a good tool to protecting a resource shared by multiple threads. Only one thread at a time can lock the mutex.
id = mutex(name)
returns the id of a new mutex, initially unlocked.
mutlock(id)
blocks the thread until the mutex is unlocked and then this thread locks it.
mutlock(id,true)
tests if the mutex can be locked, without blocking. If the mutex is unlocked it returns true
and locks the mutex, otherwise it returns false
.
mutunlock(id)
the mutex is unlocked and it is available for other threads to lock.
A timer (Linux only) periodically posts a semaphore at a periodic interval. This is useful for periodic tasks where regularity is important (minimize jitter) and where the execution time is variable.
id = timer(name, interval, sem)
creates a new timer that fires every interval
seconds (a double) and posts the semaphore sem
.
This capability is not available for MacOS, see discussion here. A workaround is to use sleep within a thread loop, but this can lead to timing jitter and drift. |
---|
The following table lists all STL functions. Where relevant there is a pointer to details of the underlying POSIX function.
STL supports a useful subset of POSIX functionality: threads, semaphores and mutexes. Each of these objects is referenced by a small integer handle. The actual POSIX object are kept in arrays within stl.c
, the maximum number of threads, semaphores and mutexes (currently 8) can be adjusted by parameters in stl.c
.
All objects have string names (MATLAB character arrays) to assist in debugging, these are shown in the log message stream.
When a resource is freed its STL handle is recycled.
Object | Handle range | Comment |
---|---|---|
thread | 0 | main thread |
thread | 1 → NTHREADS -1 |
user threads |
semaphore | 0 → NSEMAPHORES -1 |
|
mutex | 0 → NMUTEXS -1 |
|
timer | 0 → NTIMERS -1 |
An error is thrown if attempting to allocate, at any one time, more objects than the current maximum.
The C-language main function is provided by stl/main.c
which performs some initialization and then calls user.m
.
% ./user bob alice 123.5
Command line arguments are not passed through to user
but are kept by STL and made available via functions.
argc
returns the number of arguments, always one or more. In the example above it will return 4.
argv(i)
returns the i'th argument as a string. i=0 gives the name of the command, and the maximum value of i is one less than the value returned by argc
. In the example above argv(0) = './user'
which is the command used to invoke the program, and argv(3) = '123.5'
.
Detailed logging of all events to the log channel can be enabled.
stldebug(true)
Events include object creation, thread launch and exit, semaphore post and wait, mutex lock and unlock. Each entry lists the date and time (to μs precision) and the name of the thread that was executing.
An example log file enabled by debugging is:
2018-08-27 09:25:02.480656 [thread2] hello from thread2, id #2
2018-08-27 09:25:03.479300 [user] cancelling thread #2 <thread2>
2018-08-27 09:25:03.479371 [user] waiting for thread #2 <thread2>
2018-08-27 09:25:03.479435 [user] thread complete #2 <thread2>
2018-08-27 09:25:05.479844 [user] creating semaphore #0 <sem1>
2018-08-27 09:25:05.479977 [user] sem id 0
2018-08-27 09:25:06.481025 [user] thread id 1
2018-08-27 09:25:06.481079 [thread3] starting posix thread <thread3> (0xA162220)
2018-08-27 09:25:06.481109 [thread3] waiting for semaphore #0 <sem1>