Applying C - Memory Mapped Files |
Written by Harry Fairhead | ||||||||
Tuesday, 26 December 2023 | ||||||||
Page 4 of 4
Semaphore LockingTo add locking you need to make use of a semaphore which works between processes or threads. A semaphore is a more than just a lock, it is a way of signaling a state. A semaphore is created and set to a value. When a process waits on a semaphore it checks the value of the semaphore and as long as the value is greater than zero it decrements the value and continues - i.e. it has a lock. If the value is zero the process blocks and waits for the value to be greater than zero - i.e. it has to wait for the lock. Unlocking the semaphore immediately increments the value by one. Semaphores come in named and unnamed versions. You need a named semaphore to lock between processes, but an unnamed semaphore will suffice for locking threads. To create a semaphore you first need to create a variable of type sem_t, then you use the sem_open function for a named semaphore or sem_init for an unnamed semaphore. A named semaphore is removed using sem_close and an unnamed semaphore is removed using sem_destroy. After creation named and unnamed semaphores are used in the same way with sem_wait being an attempt to decrement and lock and sem_post being an unlock and increment. Notice that although we have been using the terms “lock” and “unlock”, exactly what a semaphore is used for is up to you. To create a named semaphore you use: sem_t* semptr = sem_open(Name,flags,mode,value); where Name is a null terminated string starting with / and not containing any additional slashes. It is the name of the semaphore used by all of the processes wanting to access it. The flags and mode parameters are as for opening a file. If you are creating the semaphore with O_CREATE then you have to supply value which is used to set the semaphore's initial value. If the semaphore already exists mode and value are ignored. To wait on a semaphore or obtain a lock you use: sem_wait(semptr); to release a "lock" you would use: sem_post(semptr); When a process has finished with a semaphore it can close it using: sem_close(semptr); and if necessary it can be removed using: sem_unlink(name); where name is the name used to open it. Notice that if you create a named semaphore with initial value 1 then only one process can acquire a lock and any process that tries to acquire a lock has to wait until the first process releases it. Generally the initial value gives the number of processes that can lock the semaphore without having to wait. Using a semaphore in this way the writer program is: #define _POSIX_C_SOURCE 200112L #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <inttypes.h> #include <semaphore.h> int main(int argc, char** argv) { int value = 0x55555555; int fd = shm_open("BackingFile", O_RDWR | } Notice that we unlink the semaphore just before we attempt to create it to make sure that we set its initial value. The writing program then tries to acquire a lock before writing to the memory location. If it acquires the lock, we can be sure that the reader isn't in the middle of reading data. It relinquishes the lock as soon as it can. The reader program is very similar: #define _POSIX_C_SOURCE 200112L #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <inttypes.h> #include <semaphore.h> int main(int argc, char** argv) { int value = 0x55555555; int fd = shm_open("BackingFile", O_RDWR, 0644); uint8_t *memptr = mmap(NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); sem_t* semptr = sem_open("/mySemaphore", O_CREAT, In this case we do not unlink the semaphore before opening it because we don't want to change its value if the writer has already created it - it is assumed that the write is started first as if it isn't the attempt to read the shared memory fails. That is, the semaphore mechanism doesn't stop the reader from attempting to read before the writer has started. Again the reader locks the semaphore before reading and unlocks it as quickly as possible. For either program to work we have to add the pthread library via the linker. Semaphores can be used to implement more complex types of synchronization and a full coverage of the topic would take a book in its own right. This chapter has given you a brief introduction to the many parts of the pseudo file system. In general there are two problems with making use of it. The first is discovering if there is a part of the system that covers the device or facility you want to access. The second is discovering if the machine you are working with implements it and how well. Summary
Now available as a paperback or ebook from Amazon.Applying C For The IoT With Linux
Also see the companion book: Fundamental C <ASIN:1871962609> <ASIN:1871962617> Related ArticlesRemote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info |
||||||||
Last Updated ( Wednesday, 27 December 2023 ) |