Named semaphores instead of mutex - readers writers problem without multithreading - c

My goal is to solve Readers Writers[1] problem but using only isolated processes. One process is for reader one for the writer, I should use named semaphores, so that it is possible to start subsequent reader and writers at any time - also I can't use shared memory - pure synchronization.
More info:
Provide implementation of 2 programs implementing a reader and
a writer, so that it is possible to dynamically start new processes while complying with the restrictions.
Pay attention to the properties of concurrent processing: safety and liveness.
Consider also whether you program is deadlock free.
EDIT: problem is separated to 3 files
File 1. Reader:
int main(){
sem_t *mutex;
sem_t *write;
int count=0;
mutex = sem_open("/mutex", O_CREAT, 0600, 1);
write = sem_open("/write", O_CREAT, 0600, 1);
do{
sem_wait(mutex);
count++;
if (count==1){
sem_wait(write);
}
sem_post(mutex);
printf("Critical section in readers\n");
sem_wait(mutex);
count--;
if(count==0)
sem_post(write);
sem_post(mutex);
}while(1);
}
File 2. Writer
int main(){
sem_t *write;
write = sem_open("/write", O_CREAT, 0600, 1);
do{
sem_wait(write);
printf("Critical section in writer\n");
sem_post(write);
}while(1);
return 0;
}
File 3. Deleting semaphores
int main(){
sem_unlink("/mutex");
sem_unlink("/write");
printf("Semaphores deleted \n");
return 0;
}
Problem:
when I run reader or writer with gcc -pthread file_name.c I don't
get any result, as If the code wasn't doing anything - the process is
running, the cursor is blinking but nothing happens.
[1]: READERS and WRITERS : The reading room has capacity of n
readers. Readers come to the reading room, allocate a single place, and occupy it for some time, then leave. After some time they come again and the procedure repeats. The reading room is also used by writers. However, a writer can only work when the reading room is empty, i.e. there must be no other reader nor writer. The writer occupy the room for some time, then leaves, and comes back after a while

My goal is to solve Readers Writers problem but using only isolated processes. One process is for reader one for the writer, I should use named semaphores, so that it is possible to start subsequent reader and writers at any time - also I can't use shared memory - pure synchronization.
Judging from this limited description, you can probably solve this problem by using named pipes.
I can't use shared memory
The code treats global variables counter and cnt as if they are shared between processes. They are not, each process gets a copy of those with the same value, the changes to these variables are not seen by other processes.
To use functions sem_wait and sem_post link with linker option -pthread.

You mentioned that you have to use "isolated processes", but as far as I know threads are not processes. to create a new process you have to use fork().
Differnces as mentioned here (full link with difference-table):
A process is an active program i.e. a program that is under execution.
It is more than the program code as it includes the program counter,
process stack, registers, program code etc. Compared to this, the
program code is only the text section.
A thread is a lightweight process that can be managed independently by
a scheduler. It improves the application performance using
parallelism. A thread shares information like data segment, code
segment, files etc. with its peer threads while it contains its own
registers, stack, counter etc.
in simple words - each process can have in it multiple threads ("lightweight processes").
I think you have to use fork() to create new Processes because of the word "Process" that you mentioned. also, you mentioned that you need 2 processes (one for the reader and one for the writer) so you have to fork() twice and manage these 2 processes. You can read about fork() here.
edit (semaphore implementation):
int initsem(key_t semkey, int initval)
{
int status = 0, semid;
union semun {/* should to be declared according to C standards */
int val;
struct semid_ds *stat;
ushort *array;
} ctl_arg;
if ((semid = semget(semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL)) == -1) {
if (errno == EEXIST)
semid = semget(semkey, 1, 0);
}
else { /* if created */
ctl_arg.val = initval; /* set semaphore value to the initial value*/
status = semctl(semid, 0, SETVAL, ctl_arg);
}
if (semid == -1 || status == -1) { /* failure */
perror("initsem failed");
return(-1);
}
else return semid;
}
int sem_wait(int semid)
{
struct sembuf p_buf;
p_buf.sem_num = 0;
p_buf.sem_op = -1;
p_buf.sem_flg = SEM_UNDO;
if (semop(semid, &p_buf, 1) == -1) {
perror("p(semid) failed");
exit(1);
}
else return 0;
}
int sem_post(int semid)
{
struct sembuf v_buf;
v_buf.sem_num = 0;
v_buf.sem_op = 1;
v_buf.sem_flg = SEM_UNDO;
if (semop(semid, &v_buf, 1) == -1) {
perror("v(semid) failed"); exit(1);
}
else return 0;
}

Related

How to gracefully protect/exit a multi-threaded program in C?

I have a C program where I run 3 branches of code: 2 that i started through pthread_create and the normal one.
I am wondering how to correctly protect it if my second thread fails to be created somehow.
Here is my code:
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <semaphore.h>
# include <errno.h>
typedef struct s_philo{
sem_t *first;
sem_t *second;
sem_t *stop_A;
sem_t *stop_B;
pthread_t A_thread;
pthread_t B_thread;
} t_philo;
void sem_close_safe(sem_t *sem)
{
if (sem_close(sem) == -1)
printf("Failed to close semaphore\n");
}
int free_philo(t_philo *philo)
{
if (philo->first)
sem_close_safe(philo->first);
if (philo->second)
sem_close_safe(philo->second);
if (philo->stop_A)
sem_close_safe(philo->stop_A);
if (philo->stop_B)
sem_close_safe(philo->stop_B);
free(philo);
return (1);
}
void *check_philo(t_philo *philo)
{
void *check;
check = philo;
if (!philo->first || !philo->second || !philo->stop_A || !philo->stop_B)
check = NULL;
return (check);
}
sem_t *sem_open_new_safe(const char *name, unsigned int value)
{
sem_t *sem;
sem = sem_open(name, O_CREAT | O_EXCL, 0644, value);
if (errno == EEXIST)
{
if (sem_unlink(name) == -1)
return (NULL);
sem = sem_open(name, O_CREAT | O_EXCL, 0644, value);
}
if (sem == SEM_FAILED)
return (NULL);
if (sem_unlink(name) == -1)
{
sem_close_safe(sem);
return (NULL);
}
return (sem);
}
void *A(void *p)
{
t_philo *philo;
philo = (t_philo *) p;
sem_wait(philo->stop_A);
sem_post(philo->stop_A);
return (NULL);
}
void *B(void *p)
{
t_philo *philo;
philo = (t_philo *) p;
sem_wait(philo->stop_B);
sem_post(philo->stop_B);
return (NULL);
}
int main(void)
{
t_philo *philo;
int i;
philo = malloc(sizeof(*philo));
philo->first = sem_open_new_safe("/first", 1);
philo->second = sem_open_new_safe("/second", 1);
philo->stop_A = sem_open_new_safe("/stop_A", 0);
philo->stop_B = sem_open_new_safe("/stop_B", 0);
if (!check_philo(philo))
return (free_philo(philo));
if (pthread_create(&philo->A_thread, NULL, &A, (void *)philo))
return (free_philo(philo));
if (pthread_create(&philo->B_thread, NULL, &B, (void *)philo))
return (free_philo(philo));
i = 0;
while (i++ < 100)
{
if (sem_wait(philo->first) == -1)
sem_post(philo->stop_B);
if (sem_wait(philo->second) == -1)
sem_post(philo->stop_A);
printf("%d\n", i);
sem_post(philo->second);
sem_post(philo->first);
}
sem_post(philo->stop_B);
sem_post(philo->stop_A);
pthread_join(philo->A_thread, NULL);
pthread_join(philo->B_thread, NULL);
free_philo(philo);
return (0);
}
Both of my A and B threads wait for semaphores on their first lines of code so they will never return on their own if I do not post these semaphores.
Should I pthread_join thread A ? Should I manually post some semaphores to force thread A to continue its execution and return ? Or maybe I should use pthread_detach ? I am a bit lost.
Edit: I have been asked to post more code to make it executable, but I have a lot of lines of code and it would just drown the above one. What I am looking for (if it exists) is not a guided code-specific answer, but more of a best practice to gracefully handle pthread_create errors.
Edit 2: I added the least code I could to make it runnable
The general case looks something like this pseudocode:
if (!setup_A()) {
exit(FAILURE);
}
if (!setup_B()) {
teardown_A();
exit(FAILURE);
}
if (!setup_C()) {
teardown_B();
teardown_A();
exit(FAILURE);
}
do_successful_processing();
teardown_C();
teardown_B();
teardown_A();
and you're effectively asking how to write teardown_B().
The general solution (assuming you can't just switch to C++ to use proper destructors and RAII) does not exist. The teardown is just as specific to the details of A, B, C and your application as the setup is.
I am wondering how to correctly protect it if my second thread fails to be created somehow.
The proximate answer is to tell the thread to quit (in some application-specific way), and then to join it.
The actual semantics of requesting a shutdown are specific to your code, since you wrote the function that thread is executing. Here, it should be sufficient to sem_post the semaphone thread A is waiting on.
NB. DO NOT use pthread_kill to shut down threads, if you can possibly avoid it. It's much better to write clean shutdown handling explicitly.
I am wondering how to correctly protect it if my second thread fails to be created somehow.
Easiest would be to simply call exit(1) in the case that thread creation fails. That will terminate the whole process, including all its threads. All resources owned by the process will be cleaned up by the system.
That does create a possible issue if the program wants to clean up any persistent resources, such as files or named semaphores. Often that's not a major issue, for if the program fails then it may be ok for its termination to be less tidy than if it succeeds. Nevertheless, there are ways to reduce that impact.
In particular, you can minimize the program's use of modifiable persistent resources. For example, your program would be all-around cleaner if it used unnamed semaphores instead of named ones. You would not need to watch out for existing ones when you create them, and since they are being used only within a single process, you would not need to worry about failing to clean them up before terminating.
But where you want some kind of affirmative cleanup to happen when the program terminates, you always have the option to use atexit() to register an exit handler to perform that. There are some caveats, but it's good to be aware of this option.
Should I pthread_join thread A ?
In your particular example, I see no reason to do so. It might be more appropriate in other cases.
Should I manually post some semaphores to force thread A to continue its execution and return ?
If you plan to join thread A then you need to ensure that it will, in fact, terminate. In this case, it looks like yes, you could achieve that by semaphore manipulation, but cases where it actually mattered would be more complex. Ensuring A's timely would probably not be so simple in such cases.
Or maybe I should use pthread_detach ?
There is no advantage at all to doing that in this case. Thread A will be terminated when the process terminates, regardless of whether it is detached. And presumably that's what you want in your example, for it would not make progress if it were the only live thread left in the process.

Synchronization between childs and parent processes c

im trying to implement this:
Make a C multi-process program that does the following:
A process P generates two child processes P1 and P2. The two sons P1 and P2 perform an indeterminate cycle in which generate, each second, a random integer between 0 and 100. With each draw, the children communicate the numbers generated by the parent P process which provides for adding them, printing them on the screen and storing them in one file. Process P1 must handle the SIGINT interrupt signal. In particular, at the arrival of this signal P1 must display the warning message "P1 process busy!". The program is terminated by the parent P process when it verifies that the sum of the numbers, which it has received from the child processes, assumes the value 100.
Now, I need some help with the synchronization between childs and parent. Im trying to use semaphores but it looks like impossible. what can i use to synchronize them? signals? how?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#define READ 0
#define WRITE 1
void handler(int sig){
printf("process 1 is busy\n");
}
void codeprocess1(int pd[], sem_t *sem1){
int i = 0;
int numgenerated;
while( i = 0){
signal(SIGUSR1, handler);
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem1);
}
}
void codeprocess2(int pd[], sem_t *sem2){
int i = 0;
int numgenerated;
while( i = 0){
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem2);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
sem_t *sem2 = sem_open("semaph2", O_CREAT | O_EXCL, 1, 0);
sem_t *sem1 = sem_open("semaph1", O_CREAT | O_EXCL, 1, 0);
if(pipe(pipe1)<0){
exit(1);
}
if(pipe(pipe2)<0){
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1, sem1);
break;
default:
pid2= fork();
switch( pid2){
case -1:
exit(1);
case 0:
codeprocess2(pipe2, sem2);
break;
default:
while(sum!=1000){
close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
sum = sum + numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
I'm reporting here the relevant part of the man page of sem_overview(7):
POSIX semaphores come in two forms: named semaphores and unnamed sema‐
phores.
Named semaphores
A named semaphore is identified by a name of the form /somename;
that is, a null-terminated string of up to NAME_MAX-4 (i.e.,
251) characters consisting of an initial slash, followed by one
or more characters, none of which are slashes. Two processes
can operate on the same named semaphore by passing the same name
to sem_open(3).
The sem_open(3) function creates a new named semaphore or opens
an existing named semaphore. After the semaphore has been
opened, it can be operated on using sem_post(3) and sem_wait(3).
When a process has finished using the semaphore, it can use
sem_close(3) to close the semaphore. When all processes have
finished using the semaphore, it can be removed from the system
using sem_unlink(3).
Unnamed semaphores (memory-based semaphores)
An unnamed semaphore does not have a name. Instead the sema‐
phore is placed in a region of memory that is shared between
multiple threads (a thread-shared semaphore) or processes (a
process-shared semaphore). A thread-shared semaphore is placed
in an area of memory shared between the threads of a process,
for example, a global variable. A process-shared semaphore must
be placed in a shared memory region (e.g., a System V shared
memory segment created using shmget(2), or a POSIX shared memory
object built created using shm_open(3)).
Before being used, an unnamed semaphore must be initialized
using sem_init(3). It can then be operated on using sem_post(3)
and sem_wait(3). When the semaphore is no longer required, and
before the memory in which it is located is deallocated, the
semaphore should be destroyed using sem_destroy(3).
You are trying to use unnamed semaphores in standard memory. But they are meant to synchronize threads only, not processes.
I suggest to use either named semaphores (that should be easier) or unnamed semaphores backed by shared memory (get it with shmget() or shm_open(), then use it with sem_init() - the parent and the forked processes must use the same shared memory segment to have access to the inter-process semaphore).
In fact, in your code sem1 and sem2, initialized in the main process, won't be propagated to the forked processes: they have independent memory regions and addresses, and cannot be shared.
After the edit, regarding the semaphores there are many problems:
the most logically wrong: you cannot pass the pointer of one process to another process: the addresses are not shared. Every process must independently open the semaphore and use it with his own handler.
while (i=0)... ouch, try compiling with -Wall.
You wasn't checking the return code of sem_open() it was failing with errno=13 (EACCESS)
You wasn't properly setting the permission of the semaphore... it's a (sort of) file. Note that once you crete it with the wrong permissions, it stays there and it won't be possible to create it again with the same name (until you reboot the system). You can see them with: ls -l /dev/shm, and eventually just remove them with rm.
You was requesting O_EXCL, that is, exclusive access to one process, that's not what you want. See man 2 open.
the name of the semaphore must begin with /, see man sem_overview
Here is the revised code, some comments in-line:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#include <errno.h>
#define READ 0
#define WRITE 1
#define SEM1_NAME "/semaph_1a"
#define SEM2_NAME "/semaph_2a"
void handler(int sig) {
printf("process 1 is busy\n");
}
void codeprocess1(int pd[]) {
int i = 0;
int numgenerated;
// each process must open the handle to the same named semaphore.
// they cannot share a local memory address.
sem_t *my_sem = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
// the seed for the two children must be different or they will be generating the same
// sequence of random numbers.
srand(3333);
while(i == 0) {
signal(SIGUSR1, handler);
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
void codeprocess2(int pd[]){
int i = 0;
int numgenerated;
sem_t *my_sem = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
srand(1111);
while(i == 0) {
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
// O_EXCL removed
// the mode flag must be set to 0777 for example, not "1".
// return value check added
sem_t *sem1 = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (sem1==SEM_FAILED) {
printf("semaphore sem1 creation failed, errno=%d\n", errno);
exit(1);
}
sem_t *sem2 = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (sem2==SEM_FAILED) {
printf("semaphore sem2 creation failed, errno=%d\n", errno);
exit(1);
}
if (pipe(pipe1) < 0 ) {
exit(1);
}
if (pipe(pipe2) < 0) {
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1);
break;
default:
pid2= fork();
switch( pid2) {
case -1:
exit(1);
case 0:
codeprocess2(pipe2);
break;
default:
// 100, not 1000
while (sum != 100) {
// all the "close()" calls are commented out
// close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
// close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
// sum must not be incremented
sum = numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
There is really a lot going on in your question.
As posted in the answer #Sigismondo, you are confusing multithreading with multiprocess programming. They have different method of communications.
To oversimplify threads share the same memory, so a thread can see for example values of global variables such as semaphores mutex and so on: if a thread modifies it, the other thread will be affected.
In multiprocessing when you fork(), a new process is generated with its own memory space. Right after the fork() variable values are almost the same (apart pid, ppid and so on) but they are in a different memory space: if you have a code block executed by only one process, modifying it will not affect the variables (the semaphores in your program) of the other process.
In your case: first of all if the children process do the same stuff (i.e. generate a random number) why do you have to different functions? Can't you do something like:
#include<stdlib.h>
int generateRand()
{
n = rand() % 100 + 1; //should be random in [1, 100]
}
HANDLING SIGNALS
Process P1 must handle the SIGINT interrupt signal. In particular, at
the arrival of this signal P1 must display the warning message "P1
process busy!". The program is terminated by the parent P process when
it verifies that the sum of the numbers, which it has received from
the child processes, assumes the value 100.
This is really unclear, in my opinion. The parent should catch the SIGINT signal. What should the children do? From what you say it seems they shouldn't catch that signal. In this case you must take a look at signal masks: basically you have to block the signal in the parent, the call the fork()s and then put back the original mask. Now you should go deeper but somehting like this (here)
sigset_t *parent_mask, *child_mask
//get the current mask
if (int res = sigprocmask (0, NULL, child_mask)<0)
printf("some error\n");
//make the mask block the signal
if (int res = sigaddset(child_mask, SIGINT)<0)
printf("some error in sigaddset \n");
// block the signal with the new mask
if (int res = sigprocmask (SIG_SETMASK, child_mask, parent_mask)<0)
printf("some error\n");
//do your forks: children will inherit the current mask and will not catch SIGINT
...
fork()
...
fork()
....
//set back the original mask so the parent catches SIGINT
if (int res = sigprocmask (SIG_SETMASK, parent_mask, NULL)<0)
printf("some error\n");
This answer of mine, although for multithreading should be a little clearer.
SIGNAL HANDLER
Why are you registering the signal handler in codeprocess1(int pd[])? I don't get it at all. And why SIGUSR1?
You should do it in the parent (before or after the fork()s shouldn't change since the signal is blocked for children: it depends if you want to have the user exit the program before starting the forks() or not: in the first case register the signal handler after the fork() otherwise put it at the beginning of main(). In both case you should do:
signal(SIGINT, handler);
Now the core to your program: to communicate your program you can use pipe() in a blocking way together with file descriptors: check here.
You need two file descriptors (one per child process and close the end (read/write) not used by the process).
Consider a single child process:
int p = fork();
int fd1[2]; //file descriptor for child1
int fd2[2]; //file descriptor for child2
if (p>0)//parent
{
close(fd1[1]);//close writing end
int n;
read(fd1[0], &n, sizeof(n));
//you might to call the other fork here and redo the same stuff
int p2 = fork();
if (p2>0)
{
close(fd2[1]);//close writing end
int n2;
read(fd2[0], &n2, sizeof(n2));
sum = n2+n1
if (sum==100 && exit = 1)
{
kill(p, SIGKILL);
kill(p2, SIGKILL);
}
}
}
else if(p==0)//child
{
close(fd1[0]);//close read end
int rand_n = generateRand();//or whaterver the name
wrote(fd1[1], &rand_n, sizeof(rand_n));
}
The exit condition is both based on the value of the sum (100) and the fact that CTRL+C has been pressed. The former is obvious in the code above. For the latter you can declare a global variable (I used exit) that if 0 CTRL+C has not been pressed, if 1 it has. This value is checked in the exit condition of the code above. Your handler will be responsible to write this variable:
//global variable here
int exit = 0;
void handler(int signo)
{
print("Parent busy doing stuff\n");
exit =1;
}
Note one thing exit is written by the parent since it is written ONLY in the handler which is called only by the parent and it is read in the part of the code executed only by the parent: the the children read its value it will be always 0 for them.
Being your question too general I tried to give some hints: there might be errors in my code since I haven't tried. You should study your own. If you will provide a minimal working example I will try to help.

Busy waiting and shared memory

I am currently trying to implement a single C program that creates a shared memory area for a given process then forks this process into one child, makes the child to write into a given position of the shared memory and has the father wait for until the child writes in that position. I used a simple busy waiting approach, suffering the parent process to wait until the child end his writing using a while loop. The problem is that it only works when I introduce some delay in that loop. Anyone has any idea why is this so?
Code:
int shmid;
int *shmptr;
int i, j, ret;
key_t key = SHM_KEY;
// Create shared memory segment
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600)) < 0)
{
printf("shmget error: %s\n", strerror(errno));
return -1;
}
// Attach shared memory segment
if ((shmptr = shmat(shmid, 0, 0)) == (void *) -1)
{
puts("shmat error");
return -1;
}
shmptr[6] = '%';
ret = fork();
if (ret > 0)
{/*parent*/
/*here is the loop that implements the busy waiting approach*/
while (shmptr[6] != '^') {
sleep(1);
}
for (i = 0; i < 7; i++) printf("%c", shmptr[i]);
puts("");
int status = 0;
wait(&status);
}
else
{/*child*/
shmptr[0] = 's';
shmptr[1] = 'h';
shmptr[2] = 'a';
shmptr[3] = 'r';
shmptr[4] = 'e';
shmptr[5] = 'd';
/*tell parent process ithas finished its writing*/
shmptr[6] = '^';
exit(0);
}
Volatile (see earlier comment will probably only work in a single-core scenario). Assuming you are running on a CPU with more than one cores, you will need to treat access of every location in the shared memory region atomically. If using a C++11 compliant compiler, each location of the region would need to be assumed to be of type std::atomic<int>.
Since you are probably using C, not C++, and using GCC, consider using the atomic builtins GCC Atomic Builtins.
So, your
shmptr[0] = 's';
statement should be replaced with an atomic set operator:
_sync_val_compare_and_swap(&shmptr[0], 's');
And do the equivalent for all of the sets. Then, do the equivalent in the loop to check for the return value (which will be the character you want).
The semaphore in another answer might work, but, there are no guarantees that the other locations will have made it through the CPUs write-post circuitry, through the cache controller on the source, and so on through the receiving CPU's controller, especially if the addresses being accessed span cache lines.
I would also recommend doing a sleep(0) or yield() of some sort to allow other programs to get time slices on the core that the main program is running on, otherwise, you will waste CPU resources.
You want to synchonise access to the share memory (SHM).
This, for can example, be done by using a semphore.
Before fork()ing off the child call sem_open().
Make the parent wait on sem_wait() prior to reading the SHM.
Have the child call sem_post() when done writing the SHM.
I guess that what is happening is that the child is terminating too quickly.
You might use a non-hanging waitpid(2) and add it in your loop:
/*here is the loop that implements the busy waiting approach*/
int status= 0;
while (shmptr[6] != '^') {
if (waitpid(ret, &status, WNOHANG) == ret) break;
sleep(1);
}
However, as I commented, busy waiting is always bad in Linux user-space programs (at the very least it is stressing your system). Read sem_overview(7), or alternatively, set up a pipe(7) or an eventfd(2) or a signalfd(2) and poll(2) it. Or set up a SIGCHLD signal handler (read carefully signal(7)) which just sets a volatile sigatomic_t flag to be tested in your loop.
You should also declare volatile int*shmptr; because the compiler might have optimized its use.

File segment/section/record locks in Linux threads [duplicate]

I have a multi-threaded process where a file is shared (read and written) by multiple threads. Is there any way a thread can lock one file segment so that other threads cannot access it?
I have tried fcntl(fd, F_SETLKW, &flock), but this lock only works for processes, not threads (a lock is shared between all threads in an process).
Yes - but not with the same mechanism. You'll have to use something like pthread mutexes, and keep track of the bookkeeping yourself.
Possible outline for how to make this work
Wait on and claim a process-level mutex over a bookkeeping structure
make sure no other threads within your process are trying to use that segment
mark yourself as using the file segment
Release the process-level mutex
Grab fnctl lock for process (if necessary)
Do your writing
Release fnctl lock to allow other processes to use the segment (if necessary)
Wait again on process-levelbookkeeping structure mutex (may not be necessary if you can mark it unused atomically)
mark segment as unused within your process.
Release process-level mutex
No. The region-locking feature you're asking about has surprising semantics and it is not being further developed because it is controlled by POSIX. (In fact, it is Kirk McKusick's preferred example of what's wrong with POSIX.) If there is a non-POSIX byte-range lock facility in Linux, I can't find it.
There is discussion of the problems of POSIX byte-range locking in a multithreaded world here: http://www.samba.org/samba/news/articles/low_point/tale_two_stds_os2.html.
However, if you're concerned only with threads within one process, you can build your own region-locking using semaphores. For example:
#include <stdbool.h>
#include <pthread.h>
#include <sys/types.h>
// A record indicating an active lock.
struct threadlock {
int fd; // or -1 for unused entries.
off_t start;
off_t length;
};
// A table of all active locks (and the unused entries).
static struct threadlock all_locks[100];
// Mutex housekeeping.
static pthread_mutex_t mutex;
static pthread_cond_t some_lock_released;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static void threadlock_init(void) {
for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i)
all_locks[i].fd = -1;
pthread_mutex_init(&mutex, (pthread_mutexattr_t *)0);
pthread_cond_init(&some_lock_released, (pthread_condattr_t *)0);
}
// True iff the given region overlaps one that is already locked.
static bool region_overlaps_lock(int fd, off_t start, off_t length) {
for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i) {
const struct threadlock *t = &all_locks[i];
if (t->fd == fd &&
t->start < start + length &&
start < t->start + t->length)
return true;
}
return false;
}
// Returns a pointer to an unused entry, or NULL if there isn't one.
static struct threadlock *find_unused_entry(void) {
for (int i = 0; i < sizeof(all_locks)/sizeof(all_locks[0]); ++i) {
if (-1 == all_locks[i].fd)
return &all_locks[i];
}
return 0;
}
// True iff the lock table is full.
static inline bool too_many_locks(void) {
return 0 == find_unused_entry();
}
// Wait until no thread has a lock for the given region
// [start, start+end) of the given file descriptor, and then lock
// the region. Keep the return value for threadunlock.
// Warning: if you open two file descriptors on the same file
// (including hard links to the same file), this function will fail
// to notice that they're the same file, and it will happily hand out
// two locks for the same region.
struct threadlock *threadlock(int fd, off_t start, off_t length) {
pthread_once(&once_control, &threadlock_init);
pthread_mutex_lock(&mutex);
while (region_overlaps_lock(fd, start, length) || too_many_locks())
pthread_cond_wait(&some_lock_released, &mutex);
struct threadlock *newlock = find_unused_entry();
newlock->fd = fd;
newlock->start = start;
newlock->length = length;
pthread_mutex_unlock(&mutex);
return newlock;
}
// Unlocks a region locked by threadlock.
void threadunlock(struct threadlock *what_threadlock_returned) {
pthread_mutex_lock(&mutex);
what_threadlock_returned->fd = -1;
pthread_cond_broadcast(&some_lock_released);
pthread_mutex_unlock(&mutex);
}
Caution: the code compiles but I haven't tested it even a little.
If you don't need file locks between different processes, avoid the file locks (which are one of the worst designed parts of the POSIX API) and just use mutexes or other shared memory concurrency primitives.
There are 2 ways you can do it:
Use Mutex to get a record's lock in a thread within the same process. Once the lock is acquired, any other thread in the process, mapping the file that tries to acquire the lock is blocked until the lock is released.(Preferable and only most straightforward solution available in Linux).
Semaphores and mutexes on a shared memory or a memory mapped file.

Managing a mutex in shared memory

I'm attempting the simple task of creating a mutex in shared memory. I have the following code to declare a section of shared memory, and attach it to an int*.
int *mutex;
// allocate shared memory for mutex
if ((shmid2 = shmget(IPC_PRIVATE, 4, IPC_CREAT | 0666)) < 0) {
printf("Could not allocate shared memory for mutex: %d.\n", errno);
exit(errno);
}
if ((mutex = shmat(shmid2, NULL, 0)) == (int*)-1) {
printf("Could not attach shared memory for mutex: %d\n", errno);
exit(errno);
}
// set the mutex to one
mutex[0] = 1;
Now, I attempt to define a critical section, surrounded by locking and unlocking the mutex. (Inside of one of many child processes).
while (*mutex == 0) ;
mutex[0] = 0;
// critical section
...
// end critical section
mutex[0] = 1;
However, I'm finding that this technique does not work, and two child processes can enter the critical section simultaneously, without much issue (it happens very often). So I'm wondering what I can do to fix this, without the use of pthreads.
Your options are:
Use POSIX semaphores instead of trying to implement them yourself with shared-memory spinlocks. See the documentation for semop (2) and related functions for details.
If you must use shared-memory semaphores, you will need to use an atomic compare/exchange. Otherwise, two processes can both simultaneously see *mutex == 0 and set it to 1 at the same time, without "noticing" that the other process is doing the same thing.

Resources