I am trying to create a program using shared memory blocks and obviously I have to lock them with semaphores. However I'm getting a segmentation fault when trying to initialise it (same thing happends with mutex). I have no idea what am I doing wrong here. Code looks like this:
//struct communicator_t {
// sem_t semaphore;
////////////////
//};
struct communicator_t *playerCommunicator;
//
void createCommunicator(void) {
key_t key = ftok(FILE_CONTROLLER, 0);
int sharedBlockId = shmget(key, sizeof(struct communicator_t),
IPC_CREAT);
playerCommunicator =
(struct communicator_t *) shmat(sharedBlockId, NULL, 0);
sem_init(&playerCommunicator->semaphore, 0, 1);
}
Related
I have created a struct in C. Now I want to write some data in that struct and want other process to read it.
Let call the writer be server and reader be client.
For writer code goes like:
typedef struct
{
pthread_mutex_t mutex;
char * data;
} shm_data_struct, *shm_data_struct_t;
int shmid;
char * shm_address;
shm_data_struct_t shm_ptr;
int main(int argc, char const *argv[])
{
shmid = shmget(KEY, sizeof(shm_data_struct), IPC_CREAT | 0666)
shm_address = shmat(shmid, (void*)0, 0)
shm_ptr = (shm_data_struct_t)shm_address;
//Writing into struct
shm_ptr->data = "String";
while(shm_ptr->data != '*'){
sleep(1);
}
}
For the client Side:
typedef struct
{
pthread_mutex_t mutex;
char * data;
} shm_data_struct, *shm_data_struct_t;
int main(int argc, char const *argv[])
{
int shmid;
key_t key;
char *shm;
shm_data_struct_t shm_ptr;
key = 120;
shmid = shmget(key, sizeof(shm_data_struct), 0666)
shm = shmat(shmid, NULL, 0)
/*
* Now read what the server put in the memory.
*/
shm_ptr = (shm_data_struct_t)shm;
printf("%s\n", shm_ptr->data);
shm_ptr->data = '*';
exit(0);
}
This code is giving me segmentation fault in print statement in client's code. Can anybody help what I am doing wrong?
This is your problem:
char * data;
Only the pointer (that is, an address) is being stored in shared memory. The data pointed to by the pointer is not shared, and the pointer itself will be invalid, or will point to unexpected data, in another process.
Generally speaking, SysV shared memory is a poor form of IPC, and should usually be avoided. As you've discovered, it cannot easily store even moderately complex data structures; it is also prone to race conditions, and the locking structures used to avoid that (i.e, SysV semaphores) will often create deadlocks if a process using them crashes.
I'm trying to implement a simple binary semaphore, to protect a critical variable from incorrect values, as so:
sem_init(&phore, 0, 1);//sem_t phore;
which is locking and realesing here:
void doc(){
sem_wait(&phore);
stats->npaten++;
sem_post(&phore);
printf("Doctor %d ready for duty\n%d\n",getpid(),stats->npaten);
}
doc being the worker function of 10 processes and npaten a variable of a structure in shared memory.
The expected value for npaten should be 10, however it prints out 1 everytime. Thanks in advance
EDIT: the structure in question:
struct stats{
int nptri;
int npaten;
float inicio;
float fim;
float avgtime;
}*stats;
and shared memory initialization:
void sharedmemory(){
shmid = shmget(IPC_PRIVATE, sizeof(struct stats),IPC_CREAT|0766);
stats = (struct stats *)shmat(shmid, NULL, 0);
if(shmid == -1){
perror("Couldn't create shared memory segment\n");
exit(1);
}
if(stats == (struct stats *)-1){
perror("Couldn't attach shared memory segment to the adress space\n");
exit(1);
}
printf("Shared memory created successfully\n");
}
I don't really understand how shared memory works and I am trying to write a server-client program in which the server and client talk to each other using shared memory and semaphores.
Shared memory structure:
typedef struct shared_mem{
int board[BOARD_SIZE * BOARD_SIZE];
int goal;
int client;
int direction;
sem_t sem_server;
}shared_mem;
shared_mem *msg;
Server:
int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
int direction = -1;
srand(time(NULL));
//SERVER SETS VALUES FOR SHARED MEMORY STRUCTURE
sem_wait(&msg->sem_server);
// setup the board
initialize();
// the board starts with 2 pieces
create_game_piece();
printf("pieces created");
create_game_piece();
msg->client=0;
int i;
for (i = 0; i < BOARD_SIZE * BOARD_SIZE; i++)
msg->board[i] = board[i];
sem_post(&msg->sem_server);
// game loop
while (1) {
//CLIENT READS AND CHANGES VALUES
//SERVER READS VALUES CHANGED BY CLIENT
if (!move_board(direction))
continue;
sem_wait(&msg->sem_server);
moves++;
direction=msg->direction;
if (check_win()) {
print_board(-1);
printf("congratulations! you've won in %d moves\r\n", moves);
return 0;
}
create_game_piece();
if (!has_moves_left()) {
print_board(-1);
printf("you lose! try again\r\n");
//sleep(1);
return 1;
}
sem_post(&msg->sem_server);
}
Client:
int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
atexit(on_exit2);
system("stty raw");
srand(time(NULL));
while (1) {
// CLIENT READS VALUES CHANGED BY SERVER AND CHANGES THEM
sem_wait(&msg->sem_server);
print_board(direction);
direction = keypress();
msg->direction=direction;
sem_post(&msg->sem_server);
}
Could someone please tell me how to coordinate the way the client and server access the shared memory so that it works according to the comments in the code?
SHM_UNLOCK does not do what you think. It tries to lock pages in memory not prevent access. You need a semaphore to control access to the shared memory. See semctl, semget, etc., and employ them in both the client and server for mutually exclusive access.
There are a lot of things wrong with your code.
You did not initialize the semaphore at all. For this operation where the
semaphore is located in shared memory, make sure to set the pshared argument to nonzero.
You cannot do two-way synchronization this way with only one semaphore
(otherwise you do a sem_post, that is immediately sem_waited by the same
process, hence that thread may continue, the other one doesn't get to run).
You malloc'ed msg in the client, and never pushed it to the shared memory,
thus the shared memory is still not initialized.
What do you think system("stty raw") is going to accomplish, other than opening a seriously big can of security issues?
Obviously it wasn't runnable code. I've fixed quite a few small things, but gave up after half an hour because there's just too much wrong with it. Things like comparing a char* to a shared_mem* is wrong. Enable -Wall and -Wextra on your compiler and fix all warnings you get. Your code is full of it and unfortunately all indicate serious issues.
From a design perspective, there are even more issues.
Apparently you are using a 1-D array 'board' that is global in the server. This is not proper for two reasons:
The board is always 2-dimensional, why not use a 2D array?
You use it as a global variable, accessible by all functions. This is "javascript"-style programming. Please make the board local to main and pass it to the various functions.
I am trying to create an array of structs that is shared between a parent and child processes. I am getting a segmentation fault when trying to access the array data.
I feel certain that the problem has something to do with the way I'm using pointers, as this is an area I'm not very comfortable with.
Please note that I edited out most of the code that didn't seem relevant.
/* structure of Registration Table */
struct registrationTable{
int port;
char name[MAXNAME];
int req_no;
};
main() {
/* the registrationTable is to be a shared memory space with each child
process able to access and update. No concurrency controls are
implemented. The parent process is responsible for cleaning up after
the kiddies.
*/
struct registrationTable base_table[REG_TABLE_SIZE];
for (int i = 0; i < REG_TABLE_SIZE; i++) {
base_table[i].req_no = 0;
memset(base_table[i].name, '\0', MAXNAME);
base_table[i].port = 0;
}
printf("\nMapping Shared Memory\n");
//set up shared memory space
//void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
// addr = NONE, prot = PROT_NONE, flags = MAP_SHARED
struct registrationTable *table = mmap(base_table, sizeof(base_table),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
while(1){
pid_t child = fork();
if (child == 0) {//is child
for(int i = 0; i < REG_TABLE_SIZE; i++) {
printf("\nExamining table looking for client at %s port: %d\n",
packet_reg.data, clientAddr.sin_port);
printf("\ntable[1].req_no: %d", ta[i].req_no);
//segmentation fault on next line
if (strcmp(table[i].name, packet_reg.data) == 0
&& table[i].port == clientAddr.sin_port) {
table[i].req_no++;
}
You haven't initialized content of the table after it was allocated by mmap. So it contains garbage. And so strcmp(table[i].name, packet_reg.data) has a great chance to go over allocated buffers and access e.g. non-allocated memory.
initialize table properly;
use strncmp for the comparison there.
I'm keep getting a segmentation fault from where I create thread and declare some variables in the struct...
Does anyone know why?
dispatch_queue_t *dispatch_queue_create(queue_type_t queueType){
int cores = num_cores();
printf("message-queuecreate1");
dispatch_queue_t *dispatch_queue = (dispatch_queue_t *) malloc(sizeof(dispatch_queue_t));
dispatch_queue->HEAD = NULL;
dispatch_queue->END = NULL;
//create a thread array for dispatcher and worker threads
dispatch_queue_thread_t *threads[cores+1];
threads[cores+1]= (dispatch_queue_thread_t *)malloc(sizeof(dispatch_queue_thread_t));
//create semaphores
sem_t queue_task_semaphore;
sem_t queue_thread_semaphore;
sem_t queue_wait_semaphore;
sem_init(&queue_task_semaphore, 0, 1);
sem_init(&queue_thread_semaphore,0,1);
sem_init(&queue_wait_semaphore,0,1);
dispatch_queue->queue_task_semaphore = queue_task_semaphore;
dispatch_queue->queue_thread_semaphore = queue_thread_semaphore;
dispatch_queue->queue_wait_semaphore = queue_wait_semaphore;
//create dispatcher thread
//segmentation fault #1////////////////
threads[0]->current_task=NULL;
threads[0]->queue=dispatch_queue;
pthread_create(threads[0]->thread, NULL, dispatcher_threadloop, threads[0]);
//////////////////////////////////////
if (queueType == CONCURRENT){
int i = 0;
int thread_id=0;
//create worker thread array if the type of the queue is concurrent
while(i<cores){
//create worker thread
thread_id = i+1;
//segmentation fault #2//////////
threads[i+1]->queue=dispatch_queue;
threads[thread_id]->thread=NULL;
threads[thread_id]->current_task=NULL;
pthread_create(threads[thread_id]->thread, NULL, worker_threadloop, (void *)(long)i);
////////////////////////////////
printf("thread %d is created\n",i);
i++;
}
} else {//do smth}
//segmentation fault# 3////////////////
threads[1]->thread=worker_thread;
threads[1]->queue=dispatch_queue;
threads[1]->current_task=NULL;
//////////////////////////////////////
}
return dispatch_queue;
}
Your code is riddled with problems:
Accessing threads[core + 1] is invalid. Also, you're not allocating memory for the threads[0] ... threads[core].
dispatch_queue_thread_t *threads[cores+1];
threads[cores+1]= ....;
So these will fail:
threads[0]->current_task=NULL; /* See above. */
threads[i+1]->queue=dispatch_queue; /* Again, no memory allocated. */
There could be other problems but I would start by slashing the cores+1 stuff and replacing it with:
for (i = 0; i < cores; i++) {
threads[i] = malloc(sizeof(*threads[i]));
}
Assuming
threads[]->thread
is a pthread_t (and not a pthread_t *)
You need to give the reference:
pthread_create(&threads[thread_id]->thread, NULL, worker_threadloop, (void *)(long)i);
.