C - Block others from writing to a file - c

I have multiple process writing to a FIFO file. While one of them is writing, I want to prevent other processes from writing to the file.
I am using read and write calls to access the FIFO file.
Example: There are two C-programs Server.c and Client.c. Multiple clients are writing to the FIFO file created by the server program. Server should be able to read and write from the file at any time where as only one client can access the file at a time.

Try by using locking mechanisms..try concurrent read and exclusive write mechanisms (CREW) implementations.
void ReaderThread::run()
{
...
semaphore++;
read_file();
semaphore--;
...
}
void WriterThread::run()
{
...
semaphore += MaxReaders;
write_file();
semaphore -= MaxReaders;
...
}
With this solution, up to MaxReaders threads can read from the file at the same time. As soon as a writer thread wants to modify the file, it tries to allocate all the semaphore's resources, thus making sure that no other thread can access the file during the write operation.

Related

Is it safe to use fprintf from multiple processes without using any locking mechanism? [duplicate]

Here is process a and b, both of which are multithreaded.
a forks b and b immediatly execs one new program;
a dups and freopens stderr to the logfile (a is defacto apache's httpd2.22)
b inherits the opened stderr from a. ( i am adapting apache httpd, b is my program), and b uses fprintf(stderr....) for logging
so a, b share the same file for logging
there is no lock mechanism for a, b to write log
I found that some log msg are interleaving, and a little bit of log msg got lost.
Can the two writers to the same file implicitly lock each other out?
The more important question is: If we use fprintf only within one single multithreaded process, fprintf is thread safe, i.e. one call of fprintf won't intervene another fprintf call in another thread? Many articles said this, but this is not easy to ensure myself, so I ask for help here.
A: the code for duplicate the fd is like this:
......
rv = apr_file_dup2(stderr_log, s_main->error_log, stderr_p);//dup the stderr to the logfile
apr_file_close(s_main->error_log);//here ,2 fd point to the same file description,so close one of
then
B:apache it self use this manner for logging:
......
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main, ".........");
C:for convenience,i logging in this way:
fprintf(stderr,".....\n")
I am quite sure apache and me use the same fd for file writing.
If you're using a single FILE object to perform output on an open file, then whole fprintf calls on that FILE will be atomic, i.e. lock is held on the FILE for the duration of the fprintf call. Since a FILE is local to a single process's address space, this setup is only possible in multi-threaded applications; it does not apply to multi-process setups where several different processes are accessing separate FILE objects referring to the same underlying open file. Even though you're using fprintf here, each process has its own FILE it can lock and unlock without the others seeing the changes, so writes can end up interleaved. There are several ways to prevent this from happening:
Allocate a synchronization object (e.g. a process-shared semaphore or mutex) in shared memory and make each process obtain the lock before writing to the file (so only one process can write at a time); OR
Use filesystem-level advisory locking, e.g. fcntl locks or the (non-POSIX) BSD flock interface; OR
Instead of writing directly to the log file, write to a pipe that another process will feed into the log file. Writes to a pipe are guaranteed (by POSIX) to be atomic as long as they are smaller than PIPE_BUF bytes long. You cannot use fprintf in this case (since it might perform multiple underlying write operations), but you could use snprintf to a PIPE_BUF-sized buffer followed by write.

Mutexs with pipes in C

I am sorry if this sounds like I am repeating this question, but I have a couple additions that I am hoping someone can explain for me.
I am trying to implement a 'packet queueing system' with pipes. I have 1 thread that has a packet of data that it needs to pass to a second thread (Lets call the threads A and B respectively). Originally I did this with a queueing structure that I implemented using linked lists. I would lock a Mutex, write to the queue, and then unlock the Mutex. On the read side, I would do the same thing, lock, read, unlock. Now I decided to change my implementation and make use of pipes (so that I can make use of blocking when data is not available). Now for my question:
Do I need to use Mutexs to lock the file descriptors of the pipe for read and write operations?
Here is my thinking.
I have a standard message that gets written to the pipe on writes, and it is expected to be read on the read side.
struct pipe_message {
int stuff;
short more_stuff;
char * data;
int length;
};
// This is where I read from the pipe
num_bytes_read = read(read_descriptor, &buffer, sizeof(struct pipe_message));
if(num_bytes_read != sizeof(struct pipe_message)) // If the message isn't full
{
printe("Error: Read did not receive a full message\n");
return NULL;
}
If I do not use Mutexs, could I potentially read only half of my message from the pipe?
This could be bad because I would not have a pointer to the data and I could be left with memory leaks.
But, if I use Mutexs, I would lock the Mutex on the read, attempt to read which would block, and then because the Mutex is locked, the write side would not be able to access the pipe.
Do I need to use Mutexs to lock the file descriptors of the pipe for read and write operations?
It depends on the circumstances. Normally, no.
Normality
If you have a single thread writing into the pipe's write file descriptor, no. Nor does the reader need to use semaphores or mutexes to control reading from the pipe. That's all taken care of by the OS underneath on your behalf. Just go ahead and call write() and read(); nothing else is required.
Less Usual
If you have multiple threads writing into the pipe's write file descriptor, then the answer is maybe.
Under Linux calling write() on the pipe's write file descriptor is an atomic operation provided that the size of data being written is less than a certain amount (this is specified in the man page for pipe(), but I recall that it's 4kbytes). This means that you don't need a mutex or semaphore to control access to the pipe's write file descriptor.
If the size of the data you're writing is too large then then the call to write() on the pipe is not atomic. So if you have multiple threads writing to the pipe and the size is too large then you do need a mutex to control access to the write end of the pipe.
Using a mutex with a blocking pipe is actually dangerous. If the write side takes the mutex, writes to the pipe and blocks because the pipe is full, then the read side can't get the mutex to read the data from the pipe, and you have a deadlock.
To be safe, on the write side you'd probably need to do something like take the mutex, check if the pipe has space for what you want to write, if not then release the mutex, yield and then try again.

Writing logs to a file in multithreaded application

I've written a server-client application. Now, I have to write what happens on the server to a log file. The server is written in C. I can already write what happens to the screen using printf.
So I'll just have to use fprintf instead of printf. My question is how should I handle the file?
I have Server.c source file where there is the main function
Here is the basic structure of my Server application:
Server.c
//.. some code
int main(...) {
//some code
//initialize variables
//bind server
//listen server on port
while(1)
{
//accept client
int check = pthread_create(&thread, NULL, handle_client,&ctx);//create new thread
//..
}//end while
return EXIT_SUCCESS;
}//end main
handle_client is a function which handles clients in a new thread.
How should I make the server log? I will have one text file for example SERVERLOG.log, but there are many clients on the server. How should I handle multiple access to this file?
One way is to create file when I start the server, open it, write in it, close it.
If a client wants to write in the file, then it should open the file to write in it and then close it.
But there is still a problem when more clients want to write in this file....
A common solution is to have a printf-like function, that writes all output first to a buffer, then locks a semaphore, do the actual writing to file, and unlocks the semaphore. If you are worried about the actual writing being slow, you can instead have a queue where all log messages gets inserted, and let another thread take items from the queue and write them to the file, you still have to protect the queue with e.g. a semaphore, but it should be quicker that doing I/O.
As for the actual file, either open it in the main thread and leave it open. Or if you have a special logging thread with queue then let that thread do the opening. Anyway, you don't need to keep opening/closing it every time you want to write something to it, the important part is to protect it from being written to by multiple threads simultaneous.
Just leave it open. Open the log file at server start.
A simple way to avoid badly-interlaced output buffers is to use a separate logging process, connected by a pipe (or a named pipe). The logger just sits blocked on the read() from the pipe, and writes whatever it gets to the file. (the reader's stdin, stdout could actually point to the pipe and the file) The clients just write to the pipe (which can have been dup()d over stderr) Writes to a pipe (upto PIPE_BUF) are guaranteed to be atomic.

How to use a file as a mutex in Linux and C?

I have different processes concurrently accessing a named pipe in Linux and I want to make this access mutually exclusive.
I know is possible to achieve that using a mutex placed in a shared memory area, but being this a sort of homework assignment I have some restrictions.
Thus, what I thought about is to use locking primitives on files to achieve mutual exclusion; I made some try but I can't make it work.
This is what i tried:
flock(lock_file, LOCK_EX)
// critic section
flock(lock_file, LOCK_UN)
Different projects will use different file descriptors but referring to the same file.
Is it possible to achieve something like that? Can you provide some example.
The standard lock-file technique uses options such as O_EXCL on the open() call to try and create the file. You store the PID of the process using the lock, so you can determine whether the process still exists (using kill() to test). You have to worry about concurrency - a lot.
Steps:
Determine name of lock file based on name of FIFO
Open lock file if it exists
Check whether process using it exists
If other process exists, it has control (exit with error, or wait for it to exit)
If other process is absent, remove lock file
At this point, lock file did not exist when last checked.
Try to create it with open() and O_EXCL amongst the other options.
If that works, your process created the file - you have permission to go ahead.
Write your PID to the file; close it.
Open the FIFO - use it.
When done (atexit()?) remove the lock file.
Worry about what happens if you open the lock file and read no PID...is it that another process just created it and hasn't yet written its PID into it, or did it die before doing so? Probably best to back off - close the file and try again (possibly after a randomized nanosleep()). If you get the empty file multiple times (say 3 in a row) assume that the process is dead and remove the lock file.
You could consider having the process that owns the file maintain an advisory lock on the file while it has the FIFO open. If the lock is absent, the process has died. There is still a TOCTOU (time of check, time of use) window of vulnerability between opening the file and applying the lock.
Take a good look at the open() man page on your system to see whether there are any other options to help you. Sometimes, processes use directories (mkdir()) instead of files because even root can't create a second instance of a given directory name, but then you have issues with how to know the PID of the process with the resource open, etc.
I'd definitely recommend using an actual mutex (as has been suggested in the comments); for example, the pthread library provides an implementation. But if you want to do it yourself using a file for educational purposes, I'd suggest taking a look at this answer I posted a while ago which describes a method for doing so in Python. Translated to C, it should look something like this (Warning: untested code, use at your own risk; also my C is rusty):
// each instance of the process should have a different filename here
char* process_lockfile = "/path/to/hostname.pid.lock";
// all processes should have the same filename here
char* global_lockfile = "/path/to/lockfile";
// create the file if necessary (only once, at the beginning of each process)
FILE* f = fopen(process_lockfile, "w");
fprintf(f, "\n"); // or maybe write the hostname and pid
fclose(f);
// now, each time you have to lock the file:
int lock_acquired = 0;
while (!lock_acquired) {
int r = link(process_lockfile, global_lockfile);
if (r == 0) {
lock_acquired = 1;
}
else {
struct stat buf;
stat(process_lockfile, &buf);
lock_acquired = (buf.st_nlink == 2);
}
}
// do your writing
unlink(global_lockfile);
lock_acquired = 0;
Your example is as good as you're going to get using flock (2) (which is after all, merely an "advisory" lock (which is to say not a lock at all, really)). The man page for it on my Mac OS X system has a couple of possibly important provisos:
Locks are on files, not file descriptors. That is, file descriptors duplicated through dup(2) or fork(2) do not result in multiple instances of a
lock, but rather multiple references to a single lock. If a process holding a lock on a file forks and the child explicitly unlocks the file, the
parent will lose its lock
and
Processes blocked awaiting a lock may be awakened by signals.
both of which suggest ways it could fail.
// would have been a comment, but I wanted to quote the man page at some length

C prog: After append file, read still return 0

I've a new file, opened as read/write then 1 thread will receive from network and append binary data to that file, the other thread will read from the same file to process the binary data, but the read() always return 0, so I can't read the data, but if I using cat in command line to append data, then the program can read the data and process. I don't know why it can't notice the new data coming from network. I'm using open(), read(), and write() in this program.
Use a pipe instead of an HDD-file. Depending on your system (which you didnt tell us) there are only minor modifications to your code (which you didnt give us) to do that.
file operations are buffered. try flushing the stream?
Assuming that your read() and write() functions are the POSIX one, they share the file position, even if they are used in different threads. So your read after write was trying to read after the position at which write had written. Don't use file IO to communicate between threads. In most contexts, I'd not even use pipe or sockets for that (one context I'd use them is when the reading thread is using poll/select with other file descriptors) but simple shared memory and mutex.

Resources