Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I was reading a tutorial about shared memory and found the following statement: "If a process wishes to notify another process that new data has been inserted to the shared memory, it will have to use signals, message queues, pipes, sockets, or other types of IPC.". So what is the main advantage of using shared memory and other type of IPC for notifying only instead of using an IPC that doesn't need any other IPC type to be used, like message queue and socket for example?
The distinction here is IPC mechanisms for signalling versus shared state.
Signalling (signals, message queues, pipes, etc.) is appropriate for information that tends to be short, timely and directed. Events over these mechanisms tend to wake up or interrupt another program. The analogy would be, "what would one program SMS to another?"
Hey, I added a new entry to the hash table!
Hey, I finished that work you asked me to do!
Hey, here's a picture of my cat. Isn't he cute?
Hey, would you like to go out, tonight? There's this new place called the hard drive.
Shared memory, compared with the above, is more effective for sharing relatively large, stable objects that change in small parts or are read repeatedly. Programs might consult shared memory from time to time or after receiving some other signal. Consider, what would a family of programs write on a (large) whiteboard in their home's kitchen?
Our favorite recipes.
Things we know.
Our friends' phone numbers and other contact information.
The latest manuscript of our family's illustrious history, organized by prison time served.
With these examples, you might say that shared memory is closer to a file than to an IPC mechanism in the strictest sense, with the obvious exceptions that shared memory is
Random access, whereas files are sequential.
Volatile, whereas files tend to survive program crashes.
An example of where you want shared memory is a shared hash table (or btree or other compound structure). You could have every process receive update messages and update a private copy of the structure, or you can store the hash table in shared memory and use semaphores for locking.
Shared memory is very fast - that is the main advantage and reason you would use it. You can use part of the memory to keep flags/timestamps regarding the data validity, but you can use other forms of IPC for signaling if you want to avoid polling the shared memory.
Shared memory is used to transfer the data between processes (and also to read/write disk files fast). If you don't need to transfer the data and need to only notify other process, don't use shared memory - use other notification mechanisms (semaphores, events, etc) instead.
Depending on the amount of data to be passed from process to process, shared memory would be more efficient because you would minimize the number of times that data would be copied from userland memory to kernel memory and back to userland memory.
Related
I have a block of shared memory that multiple processes access.
To this block of memory, I have one process that writes/updates information (which I'm calling a Publisher), and I have more than one process that is reading this data (which I'm calling Subscribers).
This leads me to believe that, because I don't want the Subscribers to read in the middle of a write/update from the Publisher, I need to implement access control, to guarantee that the data currently in shared memory is fully updated before the Subscribers take it (no reading in the middle of a write).
This is the behavior I'm trying to design:
Publisher may modify shared memory, but only when no other Subscriber is currently reading from the memory.
Any Subscriber may read from shared memory, so long as the Publisher is not currently modifying it.
Subscribers may not modify shared memory, only read; therefore, Consumers are allowed to read concurrently (assuming the Publisher is not modifying the shared memory).
The first solution I thought of is a simple mutex, or semaphore of size 1. This would mean that every time the Subscribers want to fetch new information, they would need to wait for the memory to be updated by the Publisher. However, this has the unintended consequences of Subscribers having to wait for other Subscribers, and the possibility that the Publisher gets delayed or locked out of the ability to publish new data if enough Subscribers exist on the system.
The second solution I thought of was looking into shm and found SHM_LOCK and SHM_UNLOCK, which seem useful to enforce the Publisher and Subscriber roles, but otherwise just seems to help reinforce what they can do, not necessarily when they can do it.
Alternatively, I have the reverse situation elsewhere, where the Subscribers from above become Publishers, each of which may or may not set a block of shared memory to a specific value. (They are not guaranteed to write to the block of memory, but the value is guaranteed to be the same across Publishers if they do write.) The Publisher from above becomes a Subscriber.
Addendum:
Each Publisher and Subscriber is an individual process.
'Shared memory' in my question represents multiple different caches of memory, not a single unit. I do not want all shared memory locked out from Subscriber(s) when my Publisher(s) issue an update to just one of N data units.
The Publisher (from the first part) is a daemon. My logic is that I want the daemon to be doing a timely action, putting data somewhere; I don't want the daemon disturbed to any great extent by Subscribers.
My questions:
Is there a control scheme that can properly encode the logic above?
(Publisher sets and removes access, Subscribers read when accessible.)
In this context, are there better methods of publishing information to multiple processes? Or is shared memory the way to go in this situation?
What you need is referred to as a read-write lock.
These are natively supported with pthreads with pthread_rwlock_*. pthread.h. Normally pthreads would be used for threads.
In the case of multiple processes you could implement a read-write lock with semaphores. Do a little bit more reading and research and that would easy enough to figure out the rest on your own.
normally, you need two mutexes for that (or more exactly, two conds, that can share the same mutex) The reason is that only locking the acces with a complex conditional is prone to a problem where readers are continously overlapping and blocking the access to writers. When using two conds, you can give priority to the queue of writers and disallow the blocking of the resources for reading when there's a writer waiting to acquire. Well, I'm supposing that the number of writers is far less than the number or readers, as you can hit the other side, and block readers because writers are overlapping and blocking them....
The most flexible approach is probably to allow writers and readers to act in sequence (well, readers can do in parallel) using a flip-flop and preparing the swith as soon as there's a worker in the other side waiting for access.
Anyway, as you have been suggested in other responses, take a look at the read-write lock suggested in other responses.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I have the following problem statement:
Implement a function substLinesMany ... . All the specified files should be processed concurrently. If any of the files result in an error, then substLinesMany will return false otherwise return true.
Would you use threading or forking here? (have to pick one)
I would use threading over forking. Creating a new thread consumes fewer resources than creating a new process. Threads share the same address space, while forking a process requires creating a new process with a new address space. Given the nature of the function (substituting lines in a file), having a separate address space per file is not necessary.
The only drawback is that there likely is a a per-process limit on the number of simultaneous open files which might be hit while using threads. That is a manageable problem though.
A different opinion, just in case. Threading seems tempting due to the advantages mentioned by #CraigAnderson.
But don't forget the following facts:
Threading is very difficult. Shared memory means you'll have to protect critical code and data sections with locks, etc. It's a nightmare to debug.
Anecdotal evidence suggests that in most cases your parallel solution will be slower than the sequential one. The reason: cache misses. Memory is magnitudes slower than CPUs. If all your threads access all process memory all the time, all your CPUs will spend their time refreshing their cache.
The overhead of fork is much less than you think. Linux is copy-on-write, so the child process starts with the same physical memory pages as the parent. Only changed data will trigger writing new physical pages.
As you compare threading with forking, you implicitly assume a Unix OS. Threading is very useful on non-Unix systems (Windows), where process creation is a huge overhead.
Parallel programs need careful design, where each thread/process works on its own chunk of memory only, to minimize cache misses. So you'll find that using forking and some Unix stream IPC is very efficient, has minimum overhead and is much easier to debug.
The semantics of Unix IPC, especially pipes, provide an excellent and easy to use way to communicate between processes. For instance a read from a worker child's pipe blocks until results are available. Add a select loop in the parent and you have data exchange AND syncing with a simple read.
Threading is less portable than forking. If you work on a multi-core embedded system with the uClibc library instead of glibc, well, uClibc has no threading.
References:
http://esr.ibiblio.org/?p=6364
http://www.catb.org/esr/writings/taoup/html/ch07s03.html#id2923889
http://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
http://shop.oreilly.com/product/9780596000271.do The Perl Camel Book Threading chapter starts with 4 pages of warnings and discouragement
https://brendaneich.com/2007/02/threads-suck/
http://blog.codinghorror.com/threading-concurrency-and-the-most-powerful-psychokinetic-explosive-in-the-univ/
As you can see in the references, they are all big names: ESR, Ousterhout, Larry Wall, Brendan Eich, a StackOverflow founder. Magnitudes more intelligent than me, still scared stiff of threads.
I am developing a rather complex microcontroller application in C, and I have some doubts about how to "link" my shared data between the different tasks/threads without coupling them.
Until now I have used a time-sliced scheduler for running my application, and therefore there has been no need for data protection. But I want to make the application right, and I want to make it ready for an multi-threaded OS later on.
I have tried to simplify my question by using a completely different system than the actual system i am working on. I couldn't add a picture because i am a new user, but ill try and explain instead:
We got 4 tasks/threads: 3 input threads which reads some sensor data from different sensors through Hardware Abstraction Layers (HAL). The collected sensor data is stored within the task domain (ie: They wont be global!!).
Now we also got 1 output task, lets call it "Regulator". Regulator has to use (read) sensor data collected from all 3 sensors in order to generate a proper output.
Question: How will Regulator read the collected data stored in the different input tasks without coupling with other tasks?
Regulator must only know of the inputs tasks and their data by reference (ie: no #includes, no coupling).
Until now Regulator have had a pointer to each of the needed sensor data, and this pointer is set up at initialization time. This wont work in a multi-threaded application due to data protection.
I could make some getSensorValue() functions, which make use of semaphores, for each sensor value and then link these to Regulator with function pointers. But this would take up a lot of memory!! Is there a more elegant way of doing this? I am just searching for inputs.
I hope all this is understandable :)
From what you described in the question and comments it seems like you're most worried about the interfacing between Sensors and Regulators being low-memory with minimal implementation details and without knowing the explicit details of each Sensor implementation.
Since you're in C and don't have some of the C++ class features that would make encapsulation easier via inheritance, I'd suggest you make a common datapackage from each Sensor thread which is passed to Regulators rather than pass a function pointer. A struct of the form
struct SensorDataWrap {
DataType *data;
LockType *lock;
... other attributes such as newData or sensorName ...
};
would allow you to pass data to Regulators, where you could lock before reading. Similarly the Sensors would need to lock before writing. If you changed data to be a double pointer DataType **data you could make the write command only need to lock for the time it takes to swap the underlying pointer. The Regulator then just needs a single SensorDataWrap struct from each thread to process that thread's information regardless of the Sensor implementation details.
The LockType could be a semaphore, or any higher level lock object which enables single-access acquisition. The memory footprint for any such lock should only be a couple bytes. Furthermore you're not duplicating data here, so you shouldn't have any multiplicative effects on your memory size relative to sensor read-outs. The hardware you're using should have more than enough space for holding a single copy of the data from the sensors you described as well as enough flash space to accommodate the semaphore or lock objects.
The implementation details for communication are now restricted to lock, do operation, unlock and doesn't need complicated function pointers or SensorN specific header includes. It should take close to the minimal logic needed for any threaded shared data program. The program should also be transferable to other microcontrollers without major changes -- the communication only really restricted by the pressence/absence of threading and locks.
Another option is to pass a triple buffer object and do buffer flipping in order to avoid semaphores and locks. This approach needs atomic integer/bool support to be created (which you most likely have exposed by the compiler if you have semaphores). A guide to using triple buffers for concurrency can be found on this blog. This approach will use a little more active memory, but is a very slick way of avoiding most concurrency problems.
I am programming a server daemon from which users can query data in C. The data can also be modified from clients.
I thought about keeping the data in memory.
For every new connection I do a fork().
First thing I thought about that this will generate a copy of the db every time a connection takes places, which is a waste of memory.
Second problem I have is that I don't know how to modify the database in the parent process.
What concepts are there to solve these problems?
Shared memory and multi-threading are two ways of sharing memory between multiple execution units. Check out POSIX Threads for multi-threading, and don't forget to use mutexes and/or semaphores to lock the memory areas from writing when someone is reading.
All this is part of the bigger problem of concurrency. There are multiple books and entire university courses about the problems of concurrency so maybe you need to sit down and study it a bit if you find yourself lost. It's very easy to introduce deadlocks and race conditions into concurrent C programs if you are not careful.
What concepts are there to solve these problems?
Just a few observations:
fork() only clones the memory of the process it executes at the time of execution. If you haven't opened or loaded your database at this stage, it won't be cloned into the child processes.
Shared memory - that is, memory mapped with mmap() and MAP_SHARED will be shared between processes and will not be duplicated.
The general term for communicating between processes is Interprocess communication of which there are several types and varieties, depending on your needs.
Aside On modern Linux systems, fork() implements copy-on-write copying of process memory. Actually, you won't end up with two copies of a process in memory - you'll end up with one copy that believes it has been copied twice. If you write to any of the memory, then it will be copied. This is an efficiency saving that makes use of the fact that the majority of processes alter only a small fraction of their memory as they run, so in fact even if you went for the copy the whole database approach, you might find the memory usage less that you expect - although of course that wouldn't fix your synchronisation problems!
I am building an application which takes as it's input an executable , executes it and keeps track of dynamic memory allocations among others to help track down memory errors.
After reading the name of the executable I create a child process,link the executable with my module ( which includes my version of malloc family of functions) and execute the executable provided by the user. The parent process will consist of a GUI ( using QT framework ) where I want to display warnings/errors/number of allocations.
I need to communicate the number of mallocs/frees and a series of warning messages to the parent process in real-time. After the users application has finished executing I wish to display the number of memory leaks. ( I have taken care of all the backend coding needed for this in the shared library I link against).
Real-Time:
I though of 2 different approaches to communicate this information.
Child process will write to 2 pipes ( 1 for writing whether allocation/free happened and another for writing a single integer to denote a warning message).
I though of simply sending a signal to denote whether an allocation has happened. Also create signals for each of the warning messages. I will map these to the actual warnings (strings) in the parent process.
Is the signal version as efficient as using a pipe? Is it feasible ? Is there any better choice , as I do care about efficiency:)
After user's application finishes executing:
I need to send the whole data structure I use to keep track of memory leaks here. This could possibly be very large so I am not sure which IPC method would be the most efficient.
Thanks for your time
I would suggest a unix-domain socket, it's a little more flexible than a pipe, can be configured for datagram mode which save you having to find message boundaries, and makes it easy to move to a network interface later.
Signals are definitely not the way to do this. In general, signals are best avoided whenever possible.
A pipe solution is fine. You could also use shared memory, but that would be more vulnerable to accidental corruption by the target application.
I suggest a combination of shared memory and a socket. Have a shared memory area, say 1MB, and log all your information in some standard format in that buffer. If/when the buffer fills or the process terminates you send a message, via the socket, to the reader. After the reader ACKs you can clear the buffer and carry on.
To answer caf's concern about target application corruption, just use the mprotect system call to remove permissions (set PROT_NONE) from the shared memory area before giving control to your target process. Naturally this means you'll have to set PROT_READ|PROT_WRITE before updating your log on each allocation, not sure if this is a performance win with the mprotect calls thrown in.
EDIT: in case it isn't blindingly obvious, you can have multiple buffers (or one divided into N parts) so you can pass control back to the target process immediately and not wait for the reader to ACK. Also, given enough computation resources the reader can run as often as it wants reading the currently active buffer and performing real-time updates to the user or whatever it's reading for.