I´m having some trouble, trying to read the shmem.
The program writing the data is giving me no error so i don't know what to do anymore.
typedef struct
{
long id;
} data;
data *dados[MAX];
int main()
{
key_t key = 5678;
int shmid;
if (shmid = shmget(key, MAX * sizeof(data),0666) < 0)
{
perror("shmget error");
return 1;
}
if((*dados = shmat(shmid,NULL,0)) == (void*) -1){
perror("shmat");
}
for (int i = 0; i < MAX; i++)
{
printf("time:%ld\n", dados[i]->id);
printf("passed %d",i);
}
return 0;
}
if (shmid = shmget(key, MAX * sizeof(data),0666) < 0)
According to C operator order of precedence the < operator has higher precedence than the = operator. Thus the above code actually assigns the boolean shmget(key, MAX * sizeof(data),0666) < 0 result to shmid.
Use explicit bracketing to get the desired result:
if ((shmid = shmget(key, MAX * sizeof(data),0666)) < 0)
Related
So i'm currently trying to code in unix using shared memory and the fork() function, I have an array of 10 structs and I would like to put that array into shared memory so that it can be accessed by a client program. I was hoping someone could point me in the right direction on how to do this.
the code I currently have is:
// Compiler Directives
// Standard Library Inclusions
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <time.h>
//Other Inclusions
struct strProcess
{
int nPriority;
int nPid;
};
// Function Prototypes (if not included within a header file)
int frand (int nInput);
int finval (int nInput);
void fsortasc(struct strProcess pArray[],int nInput);
// Main
int main(void)
{
// Variable Declarations
int nShmid,i,arraySize,nRpriority,j, nInput;
key_t nKey;
char *ptrshm, *ptrs;
int nSize;
pid_t pid;
struct strProcess pArray[10];
struct strProcess *Array;
Array = pArray;
// Code start
nKey = 5678;
FILE *f = fopen("logfile.txt", "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
printf("please enter the amount of processes to create for this cycle between 1 and 10 \n");
scanf("%d",&nInput);
if (nInput <= 0 || nInput > 10)
{
nInput = finval(nInput);
}
printf("%d", nInput);
nSize = sizeof(pArray) * 10;
//create segment
if ((nShmid = shmget(nKey,nSize, IPC_CREAT | 0666)) <0)
{
perror("shmget");
exit(1);
}
printf("segment created \n\n");
fprintf(f, "shared memory segment created");
Array *pArray = shmat(shmid,NULL, 0);
if (Array* pArray (-1))
{
perror("shmat");
exit(1);
}
printf("segment attached \n\n");
fprintf(f, "shared memory segment attached");
for(i = 0 ; i < nInput; i++)
{
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
Array[i].nPid = getpid();
nRpriority = frand(nInput);
Array[i].nPriority = nRpriority;
printf("print job created with Pid %d and priority number %d",
getpid(), nRpriority);
fprintf(f, "print job created with Pid %d and priority number %d",
getpid(), nRpriority);
}
}
fprintf(f, " %d processes have been created", nInput);
fsortasc(pArray, nInput); /*sort array into ascending order by nRpriority values*/
// Function Definitions - in alphabetical order
int finval (int nInput)
{
while(nInput <= 0 || nInput > 10)
{
printf("please enter a number between 1 and 10 \n");
scanf("%d", &nInput);
}
return nInput;
}
int frand (int nInput)
{
int nRand;
nRand = (rand() % nInput)+1; /*set nRand == a random number
inbetween nInput and 1*/
return nRand; /*return the random number*/
}
void fsortasc(struct strProcess pArray[],int nInput)
{
struct strProcess temp; /*temporary storage for elements being swapped*/
int i, j;
for (i = 0; i < nInput - 1; i++)
{
for (j = 0; j < (nInput - 1-i); j++)
{
if (pArray[j].nPriority > pArray[j + 1].nPriority) /*if the current element is greater than the next element*/
{
temp = pArray[j];
pArray[j] = pArray[j + 1];
pArray[j + 1] = temp;
}
}
}
I have an array of 10 structs and I would like to put that array into shared memory ? It's very simple, first create array 10 struct variable and then create the shared memory using shmget of required size and then attach that shared memory with pointer and finally copy array of 10 structs into pointer attached with shmat. I added below simple code to understand your requirement.
typedef struct company {
int emp_id;
}cmp;
int main(int argc,char *argv[]) {
cmp cmp_info[10];
int shm_id, sze = sizeof(cmp_info) ,i;
/* I have an array of 10 structs -- with some data like emp_id*/
for(i=0 ;i<10 ;i++) {
printf("\n enter emp % Id \n",i);
scanf("%d",&cmp_info[i].emp_id);
}
/* create the shared memory of 'sze' size. */
shm_id = shmget(10,sze, IPC_CREAT | 0664);
perror("shmget");
/* attach the shared memory with shm_id */
cmp *shm_ptr = shmat(shm_id, NULL, 0);
perror("shmat");
/* I have an array of 10 structs and I would like to put that array into shared memory */
shm_ptr = cmp_info;//now shared memory contains array of 10 struct data
/** print using shm_ptr to verify **/
for(i=0;i<10;i++) {
printf("Employee[%d] Id is : [%d]\n",i,shm_ptr[i].emp_id);
}
/* once above things are done clients program can read from shared memory */
/** finaly de-atach the shared memory */
shmdt(shm_ptr);
}
Below snapshot is for your code, Explanation is in comments.
struct strProcess {
int nPriority;
int nPid;
};
int main(int argc,char *argv[]) {
// Variable Declarations
int nShmid,i,arraySize,nRpriority,j, nInput;
key_t nKey;
char *ptrshm, *ptrs;
int nSize;
struct strProcess pArray[10];//array of 10 structure
struct strProcess *Array;
//Array = pArray;
nKey = 5678;
FILE *f = fopen("logfile.txt", "w");
if(f == NULL) {
printf("Error opening file!\n");
exit(1);
}
nSize = sizeof(pArray);
//create segment
if((nShmid = shmget(nKey,nSize, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
else {
perror("shmget");
fprintf(f, "\n shared memory segment created\n");
}
Array = shmat(nShmid, NULL, 0);
perror("shmat");
/** loop to create exaCtly 10 process */
nInput = 10; /** call finval function **/
for(i = 0 ; i < nInput; i++) {
if(fork() == 0) {
srand(getpid());
Array[i].nPid = getpid();
nRpriority = rand()%10 + 1;//putting random no b/w 1 to 10..u can call your function also
Array[i].nPriority = nRpriority;
fprintf(f, "\nprint job created with Pid [%d] and priority number [%d]\n",
Array[i].nPid, Array[i].nPriority);
break;//must to avoid repeating
}
else {
;//parent does nothing
}
}
shmdt(Array);
//fprintf(f,"\n total [%d] processes have been created\n",nInput);
/* call fsortasc(pArray, nInput); */
fclose(f);
}
I hope it helps.
Problem:
All processes have an array of elements.
Producer stores a value in his array.
All consumers(n) must store this value on their array before a producer can produce additional element.
All consumers should store the element and wait until the producer creates a new one.
So in my implementation I'm using three semaphores: all(as a barrier)=1, new=0 and a mutex=1. I'm also using a shared counter=0 to count how many consumers have read the element.
Code:
#include <time.h>
#include <sys/shm.h>
#include "stdio.h"
#include "sys/sem.h"
#include "stdlib.h"
#include "unistd.h"
int sem_id;
int shmid;
typedef struct sharedMemory{
int value;
}sharedMemory;
union semun {
int val;
struct semid_ds * buf;
unsigned short * array;
};
#define M 4
#define N 2
typedef enum semIndex{
mutex= 0,
all=1,
new=2
}semIndex;
int sem_init(semIndex index,int val){
union semun sem_union;
sem_union.val = val;
if (semctl(sem_id, index, SETVAL, sem_union) == -1) return 0;
return 1;
}
int up(semIndex index) {
struct sembuf sem_b;
sem_b.sem_num = index;
sem_b.sem_op = 1;
if (semop(sem_id, &sem_b, 1) == -1) {
perror("Failed to up");
return 0;
}
return 1;
}
int down(semIndex index) {
struct sembuf sem_b;
sem_b.sem_num = index;
sem_b.sem_op = -1;
if (semop(sem_id, &sem_b, 1) == -1) {
perror("Failed to up");
return 0;
}
return 1;
}
void *getShMemory(int memory) {
shmid = shmget((key_t)1234+memory, sizeof(sharedMemory), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
void* shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
return shared_memory;
}
int main(void){
srand(getpid() + rand()%500);
int *array = malloc(M * sizeof(int));
for (int i = 0; i < M; ++i) {
array[i] = rand() % 20;
}
sem_id = semget(6846, 3, 0666 | IPC_CREAT);
sharedMemory *sharedMem = (sharedMemory*) getShMemory(2);
sem_init(all,1);
sem_init(mutex,1);
sem_init(new,0);
pid_t pid = fork();
if (pid>0){
for (int i = 0; i < M; ++i) {
down(all);
down(mutex);
sharedMem->value = array[i];
up(mutex);
up(new);
}
for (int j = 0; j < M; ++j) {
printf("%d,",array[j]);
}
putchar('\n');
}
else{
sem_id = semget(6846, 3, 0666 | IPC_CREAT);
int *array = malloc(M*sizeof(int));
sharedMemory* consumerMem = (sharedMemory*)getShMemory(1);
down(new);
consumerMem->value = 0;
for(int i=0;i<N;++i){
if(fork() == 0) {
for (int j = 0; j < M; ++j) {
down(mutex);
consumerMem = (sharedMemory*)getShMemory(1);
sharedMemory *sharedMem = (sharedMemory*) getShMemory(2);
array[j] = sharedMem->value;
consumerMem->value++;
up(mutex);
if (consumerMem->value == N) {
down(mutex);
consumerMem->value = 0;
up(mutex);
up(all); //signal producer to create new element
}
down(new); //wait for new element
up(new); //unblock one more consumer
}
for (int j = 0; j < M; ++j) {
printf("%d,",array[j]);
}
putchar('\n');
exit(0);
}
}
}
}
Sometimes it works as intended so it ought to be a race condition but I can't pinpoint it.Any clues?
Update:
I managed to run debug with Clion. I can't replicate the problem with the debugger so it's even harder to pinpoint the problem.
I am currently working on a producer-consumer implementation using C.
First, I create a buffer on the shared memory of a variable length that is given by the user in the consumer process.
Then, in the producer process, I need to access the shared memory and puts new data to the buffer so the consumer can consume.
Below is the consumer code:
#include "common.h"
#include <unistd.h>
int fd;
int errno;
int MY_LEN = 0;
Shared* shared_mem;
char *job[4];
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_CREAT | O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
ftruncate(fd, sizeof(Shared) + MY_LEN*sizeof(char *));
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared) + MY_LEN*sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int init_shared_memory() {
shared_mem->data = 0;
int i;
for(i = 0; i < shared_mem->length; i++)
{
shared_mem->arr[i] = 0;
// shared_mem->arr[i] = (char *)calloc(1, sizeof(char*));
}
sem_init(&(shared_mem->mutex), 1, 1);
}
int init_job(){
int i;
for(i = 0; i < 4; i++)
{
job[i] = (char *)malloc(sizeof(char *));
}
}
int take_a_job(int index){
init_job();
char *ds = strdup(shared_mem->arr[index]);
job[0] = strtok(ds, "-");
int i = 1;
while(i < 4)
{
job[i] = strtok(NULL, "-");
i++;
}
// remove the job from the buffer
shared_mem->arr[index] = NULL;
}
int consume_job(int index){
printf("\nPrinter starts printing the job %s, %s pages from Buffer[%d]. The duration is %s seconds and the source is %s.\n",job[3], job[2], index, job[1], job[0]);
sleep(atoi(job[1])); // sleep for job[1] seconds.
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
init_shared_memory();
MY_LEN = atoi(argv[1]); // the first parameter following ./printer = the length of the buffer
shared_mem->length = MY_LEN;
//shared_mem->arr = (int*) &shared_mem->arr;
int index = 1;
*(shared_mem->arr) = "1-10-5-6";
*(shared_mem->arr + 1) = "2-5-2-7";
*(shared_mem->arr + 2) = "3-20-10-8";
*(shared_mem->arr + 3) = "4-7-4-9";
take_a_job(index);
int i;
for(i = 0; i < shared_mem->length; i++){
printf("\n\n%d set %s\n", i, shared_mem->arr[i]);
}
consume_job(index);
printf("\n\nHello second check\n\n");
while (1) {}
return 0;
}
Here is the producer code:
#include "common.h"
int fd;
Shared* shared_mem;
char *job;
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int create_a_job(int args, char *argv[]){
int i;
job = (char *)calloc(8, sizeof(char *));
if(args != 5)
return 0; //the parameters are not correctly formatted
else{
for(i = 1; i < args; i++)
{
if(i > 1)
strcat(job, "-");
strcat(job, argv[i]);
}
}
strcat(job, "\0");
printf("\nthe job is %s\n", job);
}
int put_a_job(){
printf("shared_mem->length is %d\n\n", shared_mem->length);
int i;
for(i = 0; i < shared_mem->length; i++)
{
if(*(shared_mem->arr + i) == 0)
{
//shared_mem->arr[i] = (char *)malloc(sizeof(job));
//strcpy(shared_mem->arr[i], job);
*(shared_mem->arr + i) = (char *)job;
printf("\n\nThe index is %d\n", i);
//printf("\n\nthe argument is %s at %d\n", job, i);
return i;
}
}
printf("\n\nThe index is %d\n", i);
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
// create a job with the parameters
int result = create_a_job(args, argv);
if(result == 0)
{
printf("Not the right parameters.\n");
printf("Plase enter client ID, job duration, number of pages and job ID.\n");
return 0;
}
int i;
put_a_job();
for (i=0; i < shared_mem->length; i++) {
printf("the argument is %s at %d\n", (char *)(shared_mem->arr + i), i);
}
printf("\n\n");
return 0;
}
The common.h file is
#ifndef _INCLUDE_COMMON_H_
#define _INCLUDE_COMMON_H_
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
// from `man shm_open`
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <string.h>
#include <semaphore.h>
#define MY_SHM "/JIT"
typedef struct {
sem_t mutex;
int data;
int length; // the length of the buffer
char *arr[0];
} Shared;
#endif //_INCLUDE_COMMON_H_
I first run ./consumer 10 & to allocate a buffer of length 10 and after, I run ./producer 1 2 3 4 to put the job to the buffer and print the buffer, I got garbage values
Any help would be really appreciated! Thank you!
Instruction
*(shared_mem->arr + i) = (char *)job;
is storing the pointer job into the shared mem, not the pointed value.
Maybe you want to use a strncpy.
You cannot share memory address between processes, because of Linux uses virtual memory. To make the story short an address in a process is not valid for a different process.
Be aware that you have a memory leakage because you never call free() for the allocated job.
The task was to create simulation of warehouse's work. Producers (in an amount of argv[2]) create random number of "goods" (totally argv[1]), and consumers (in an amount of argv[3]) get random number of these goods. The full code is below.
I got segmentation error and tried to debug it and got the following:
Program received signal SIGSEGV, Segmentation fault.
__new_sem_init (sem=0x37, pshared=0, value=1) at sem_init.c:44
44 sem_init.c: No such file or directory
I think the problem is in address-of operator here
sem_init(&(shared->mutex), 0, 1);
How should I change the code to make it work?
Thanks a lot!
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#define NBUFF 10
#define MAXNTHREADS 100
#define min( a, b ) ( ( a < b) ? a : b )
int nitems, nproducers, nconsumers;
typedef struct shared_s
{
int buff[NBUFF];
int nput;
int nputval;
int nget;
int ngetval;
sem_t mutex, nempty, nstored;
} sharedtype;
int main(int argc, char **argv)
{
sharedtype * shared;
key_t key;
int shmid, semid;
int i, j, prodcount[MAXNTHREADS], conscount[MAXNTHREADS];
shared = mmap(NULL, sizeof(sharedtype),
PROT_READ | PROT_WRITE, MAP_SHARED, -1, 0);
/* Wrong argv */
if (argc != 4)
{
printf("usage: newconsumer <#items> <#producers> <#consumers>\n");
exit(1);
}
nitems = atoi(argv[1]);
nproducers = min(atoi(argv[2]), MAXNTHREADS);
nconsumers = min(atoi(argv[3]), MAXNTHREADS);
pid_t chpidpr [nproducers];
pid_t chpidcon [nconsumers];
/* initilising semaphores */
sem_init(&(shared->mutex), 0, 1);
sem_init(&(shared->nempty), 0, NBUFF);
sem_init(&(shared->nstored), 0, 0);
for (i = 0; i < nproducers; i++) {
prodcount[i] = 0;
switch (chpidpr[i] = fork())
{
case -1:
printf("fork error");
return 1;
case 0:
for (;;)
{
sem_wait(&shared->nempty);
sem_wait(&shared->mutex);
if (shared->nput >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->nempty));
sem_post(&(shared->mutex));
return 0;
}
shared->buff[(shared->nput) %NBUFF] = shared->nputval;
(shared->nput)++;
(shared->nputval)++;
sem_post(&(shared->mutex));
sem_post(&(shared->nstored));
prodcount[i] += 1;
}
}
}
for (i = 0; i < nproducers; i++)
{
printf("producer count[%d] = %d\n", i, prodcount[i]);
}
for (i = 0; i < nconsumers; i++) {
conscount[i] = 0;
switch (chpidcon[i] = fork())
{
case -1:
printf("error");
return 1;
case 0:
for (;;)
{
sem_wait(&(shared->nstored));
sem_wait(&(shared->mutex));
if (shared->nget >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->mutex));
return 0;
}
j = shared->nget % NBUFF;
if (shared->buff[j] != shared->ngetval)
{
printf("error: buff[%d] = %d\n", j, shared->buff[j]);
}
shared->nget++;
shared->ngetval++;
sem_post(&(shared->mutex));
sem_post(&(shared->nempty));
conscount[i] += 1;
}
}
}
for (i = 0; i < nconsumers; i++)
{
printf("consumer count[%d] = %d\n", i, conscount[i]);
}
/* destroying semaphores */
sem_destroy(&(shared->mutex));
sem_destroy(&(shared->nempty));
sem_destroy(&(shared->nstored));
exit(0);
}
It looks like your mmap call has failed and return -1. You aren't checking for this condition.
I did a quick addition, and it looks like mutex is at an offset of 56, or 0x38 from the base of sharedtype. Based on the crash report, sem = 0x37, which would be the address of shared->mutex if shared == -1.
I can't find any documentation on why one would call mmap with fd == -1, but I think this may be the source of the issue, combined with not validating the result.
I know what every command does within my code, I just don't know the reasons they're there in the first place. This is insanely difficult to search answers for as my questions relate mostly to my own program. Apologies if it's still un-answerable, I will endeavor to improve my future questions :).
I need to write a program that can communicate across shared memory, taking turns to create and delete processes. I'm trying to understand the piece of code I was given, in particular the bit below. At the very bottom I've included the whole producer code in case it helps anyone answer my question.
THE QUESTION: Why is *randNum incremented past 101 when later, the condition for it to print the output IS it being equal to 101?
Does this hint at the Consumer having to change the value contained in the location *randNum in order for the condition to be met?
for(A = 0; A < size; A++) // for loop to reset all priority values so that they are clear to be used in the next set
{
*randNum = 101;
*randNum++;
}
The if command later on:
if(*randNum == 101)
{
*randNum = rand() % (100 - 1) + 1;
*pidNum = getpid();
printf("priority: %d Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
As promised, full program below for completion purposes (trying to make it easier on you and prevent questions; also to provide context)
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
void shm2sz(int size);
int main(int argc, char *argv[])
{
int shmid, A, B, count, *shm, *randNum, *pidNum, pid, *memSig;
key_t key;
int size = atoi(argv[1]);
int shmsz = (size * 2) + 1; // declaring size of shared mem to be twice the size of user input, + 1 for owner ID
int x = 0;
int noToCreate = atoi(argv[2]);
shm2sz(shmsz);
key = 2060; // Identifier key for SharedMem
shmid = shmget(key, shmsz, IPC_CREAT | 0666); //creating Sharedmem
if(shmid < 0) // variable if sharedmem is less than 0, print error.
{
perror("shmget"); // eror mesage print
exit(1);
}
shm = shmat(shmid, NULL, 0); //Attach to shared mem, if fails.. proceed with error message
if(shm == (int *) -1) // eror message
{
perror("shmat");
exit(1);
}
randNum = shm; // declare randNum equal to shm
pidNum = shm + size; // set pid to the first bit of the second part of the shared mem
memSig = shm + shmsz; // set memsig as final value in shared mem
*memSig = 0;
for(A = 0; A < size; A++) // for loop to reset all priority values so that they are clear to be used in the next set
{
*randNum = 101;
*randNum++;
}
count = 0; // set count back to 0
randNum = shm; //check randNum equal to shm
pidNum = shm + size;
while(*memSig != 2)
{
while(*memSig == 1) // set memsignature to sleep while..
{
sleep(1);
}
for(B = 0; B < noToCreate; B++)
{
pid = fork();
if(pid == -1)
{
perror("Error forking");
exit(1);
}
else if(pid > 0)
{
wait(0);
}
else
{
srand(getpid());
while(x == 0)
{
if(*randNum == 101)
{
*randNum = rand() % (100 - 1) + 1;
*pidNum = getpid();
printf("priority: %d Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
else
{
*randNum++;
*pidNum++;
}
}
exit(0);
}
} /* Closes main for loop */
if(*memSig == 0)
{
*memSig = 1;
}
} /* Closes main while loop */
}
void shm2sz(int size)
{
int shmid, *shm2;
key_t key;
key = 9876;
shmid = shmget(key, 2, IPC_CREAT | 0666);
if(shmid < 0)
{
perror("shmget2");
exit(1);
}
shm2 = shmat(shmid, NULL, 0);
if(shm2 == (int *) -1)
{
perror("shmat2");
exit(1);
}
*shm2 = size;
}
The operator precedence for the postfix increment operator is higher than the pointer dereference operator. This means that *randNum++ actually increases the pointer randNum.
If you want to increment the value pointed to by randNum you have to use parentheses:
(*randNum)++;