-1

I have coded little program that uses shared memory that sends bytes around basicly. The problem I have is, I think, that I'm getting stuck in the child process (it prints Process 2: 5000 and then nothing).

Can anyone help me? I'd really appreciate it!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
 
int main() {
    int sem_id;
    int shm_id;

    key_t key = ftok("shared_memory", 1); // Create key shared memory
    key_t keytwo = ftok("semaphore", 1); // Create key semaphore
    shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666); // Create shared memory
    sem_id = semget(keytwo, 1, IPC_CREAT | 0666); // Create Semaphore
 
    if((shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666)) == -1){ // -1 indicates error
     perror("semctl");
     exit(1);
    } else {
    printf("Shared memory created with id: %d \n", shm_id);
    }
 
    if((sem_id = semget(keytwo, 1, IPC_CREAT | 0666)) == -1){ // -1 indicates error
    perror("semctl");
    exit(1);
    } else {
    printf("Sephamore created with id: %d \n", shm_id);
    }
 
    struct sembuf sem_lock = {0, -1, 0}; // Struct for semop to lock
    struct sembuf sem_unlock = {0, 1, 0}; // Struct for semop to unlock
 
    char *data = (char *)shmat(shm_id, NULL, 0); // Connect Shared-Memorys to Process
 
    pid_t pid;
 
    semctl(sem_id, 0, SETVAL, 1); //initialize the semaphore with value 1
    if((semctl(sem_id, 0, SETVAL, 1)) == -1){ // -1 indicates error
     perror("semctl");
     exit(1);
    } else {
    printf("Sephamore initialized \n");
    }
 
    pid = fork();
 
    if(pid < 0){
        printf("Error");
        return 1;
    }
 
    int p = 1;
    int c = 1;

    //16777216 = 1024 * 16384 
    char *message = (char *) malloc(16777216);
    char *read = (char *) malloc(16777216);
 
    for (int KiB = 1; KiB <= 16384; KiB *= 2) {
        int bytes = KiB * 1024;

         for(int i = 0; i < 1000; i++){
 
            if (pid == 0) {
                // Process 2:
                semop(sem_id, &sem_lock, 1);
                memcpy(read, data, bytes); //"read" data
                //printf("%s \n", read) //print to check whether read worked
                semop(sem_id, &sem_unlock, 1);
                //print to check race condition
                printf("Process 2 print: %d \n", p);
                p++;
            } else {
                // Process 1:
                for (int i = 0; i < bytes; ++i) {
                    message[i] = 'a';
                }
                semop(sem_id, &sem_lock, 1);
                printf("%d", sem_id);
                memcpy(data, message, bytes);
                semop(sem_id, &sem_unlock, 1);
                //print to check race condition
                printf("Process 1 print: %d \n", c);
                c++;
                wait(NULL);
                }
        }
        
    }
  
    shmdt(data); // Remove shared-memory from process
    shmctl(shm_id, IPC_RMID, NULL); // Delete shared memory
    semctl(sem_id, 0, IPC_RMID); // Delete semaphore
 
    return 0;
}

I was expecting the processes to alternate.

I have tried: Place locks differently, Add locks, Remove locks, Remove unlocks, sleep(1).

Riuma
  • 1
  • 2
  • you never test the return codes of any of those calls – pm100 Jan 26 '23 at 19:24
  • which calls are you referring to? do you mean, whether or not the lock actually did anything? – Riuma Jan 26 '23 at 19:25
  • shmget, semget,semctl,semop – pm100 Jan 26 '23 at 19:30
  • 2
    `if (sem_id =! 0)` doesn't do what you think it does, or is a typo. The compiler warns about it if you enable more warnings. Here you are _setting_ `sem_id` to 1. – pmacfarlane Jan 26 '23 at 19:55
  • I have since changed this, but thank you very much! – Riuma Jan 26 '23 at 20:06
  • I'm slightly worried that you're not showing us the code that fails, because with the `=!` error you should have been logging `Error initialize failed` and exiting. But you didn't report seeing that. – pmacfarlane Jan 26 '23 at 20:19
  • `if(shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666) == -1)` and other lines like this don't do what you think they do. You need more `()`. Your compiler will tell you that if you [enable more warnings](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings/57842757#57842757). – pmacfarlane Jan 26 '23 at 20:32
  • None of the many versions of your code have shown a race condition, they all simply immediately fail. You need to post a version of your code that matches the symptoms you are describing. Make sure you can compile it and run it yourself, and that it still shows the issue. And please, please, [enable more warnings](https://stackoverflow.com/questions/57842756/why-should-i-always-enable-compiler-warnings/57842757#57842757) – pmacfarlane Jan 26 '23 at 20:37
  • @pmacfarlane You were right, the compiler I was previously using somehow made this work, even though it shouldn't have. The current version does not compile properly, thank you. – Riuma Jan 26 '23 at 21:13
  • The current version compiles fine for me, but does not run. How many compilers are you using? – pmacfarlane Jan 26 '23 at 21:25
  • @pmacfarlane I was using onlinegdb, I am now running via gcc on a VM. But you are right, it compiles, it runs into segfault – Riuma Jan 26 '23 at 21:34
  • I have since changed the coding some more, it doesn't segfault anymore, it still doesn't work, but I suppose it's progress. It seems to stuck in the child process at some point. – Riuma Jan 26 '23 at 22:14
  • What is the waitI() for? It's inside 2 nested for loops. This might be the most baroque race-condition example I've ever seen. – pmacfarlane Jan 27 '23 at 01:26
  • Compiling with the address sanitiser shows that one of your memcpy() is going out of bounds. I don't have the energy to chase that, having spent hours just trying to get a version of your code to run. Good luck. – pmacfarlane Jan 27 '23 at 01:30
  • Stop using compound expressions. Yes, that sometimes results in inelegant code, eg. an extra syscall before a loop that seems like unnecessary code duplication. Doesn't matter - stop using compound expressions unless you really like debugging nightmares:) – Martin James Jan 27 '23 at 06:29

1 Answers1

0

I am not saying this is the reason for the failure, but you are not testing any return codes from these functions. Always test returns, especially if you are seeing problems and / or are new to calls

taking semctl as an example. looking here https://man7.org/linux/man-pages/man2/semctl.2.html you see that it returns a value indicating the result

so here

semctl(sem_id, 0, SETVAL, 1); //initialize the semaphore with value 1

you should do

if(semctl(sem_id, 0, SETVAL, 1) == -1){ // -1 indicates error
     perror("semctl");
     exit(1);
 }
pm100
  • 48,078
  • 23
  • 82
  • 145
  • First of all, thank you! I hope I understood this correctly, and I do now check the return values, they seem fine? But even though that didn't fix it, it's still really good to know! – Riuma Jan 26 '23 at 19:59