I need to write barrier for process synchronisation. I did and it was working until I put struct barrier in shared memory. My code is as follows:
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
void nanosleep2(long t)
{
struct timespec a;
a.tv_sec = 0;
a.tv_nsec = t;
nanosleep(&a, NULL);
}
struct barrier
{
int n; // number of processes
sem_t mutex;
int count;
sem_t bar;
};
void init(struct barrier * b, int n)
{
b->n = n;
b->count = 0;
sem_init(&b->mutex, 0, 1);
sem_init(&b->bar, 0, 0);
}
void destroy(struct barrier * b)
{
sem_destroy(&b->mutex);
sem_destroy(&b->bar);
}
void wait(struct barrier * b)
{
sem_wait(&b->mutex); // It seems that some processes never get acces to mutex, but isn't it impossible?
++(b->count);
printf("Horse is there!, %d/%d\n", b->count, b->n);
if (b->count == b->n)
{
printf("the barierr is open!\n");
sem_post(&b->bar);
}
sem_post(&b->mutex);
sem_wait(&b->bar);
sem_post(&b->bar);
}
struct barrier * barr_open(const char * name)
{
int fd = shm_open(name, O_RDWR | O_CREAT, 0666);
ftruncate(fd, sizeof(struct barrier));
struct barrier * res = mmap(NULL, sizeof(struct barrier), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
close(fd);
return res;
}
void barr_close(struct barrier * barr, const char * name) // if name is not NULL, it also unlinks
{
munmap(barr, sizeof(struct barrier));
if (name != NULL)
shm_unlink(name);
}
const int N = 5; // number of horses
void * horse(void * _)
{
struct barrier * barr = barr_open("/barieraa");
nanosleep2((rand()%200)+10);
wait(barr);
barr_close(barr, NULL);
return NULL;
}
int main()
{
srand(time(NULL));
struct barrier * barr = barr_open("/barieraa");
init(barr, N);
sleep(1);
int i;
for (i = 0; i < N; i++)
{
pthread_t t;
pthread_create(&t, NULL, horse, NULL);
pthread_detach(t);
nanosleep2(rand()%200);
}
sleep(1);
destroy(barr);
barr_close(barr, "/barieraa");
return 0;
}
So, the first printf in wait() only three or four horses are able to reach. Probably something grabs mutex and doesn't return, but is it possible? Why barrier itself works, shared memory itself works, but they both together don't want?
Related
In fork child, if we modify a global variable, it will not get changed in the main program.
Is there a way to change a global variable in child fork?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int glob_var;
main (int ac, char **av)
{
int pid;
glob_var = 1;
if ((pid = fork()) == 0) {
/* child */
glob_var = 5;
}
else {
/* Error */
perror ("fork");
exit (1);
}
int status;
while (wait(&status) != pid) {
}
printf("%d\n",glob_var); // this will display 1 and not 5.
}
You can use shared memory (shm_open(), shm_unlink(), mmap(), etc.).
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static int *glob_var;
int main(void)
{
glob_var = mmap(NULL, sizeof *glob_var, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*glob_var = 1;
if (fork() == 0) {
*glob_var = 5;
exit(EXIT_SUCCESS);
} else {
wait(NULL);
printf("%d\n", *glob_var);
munmap(glob_var, sizeof *glob_var);
}
return 0;
}
Changing a global variable is not possible because the new created process (child)is having it's own address space.
So it's better to use shmget(),shmat() from POSIX api
Or You can use pthread , since pthreadsare sharing the globaldata and the changes in global variable is reflected in parent.
Then read some Pthreads tutorial.
Here is an alternative solution.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
typedef struct
{
int id;
size_t size;
} shm_t;
shm_t *shm_new(size_t size)
{
shm_t *shm = calloc(1, sizeof *shm);
shm->size = size;
if ((shm->id = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0)
{
perror("shmget");
free(shm);
return NULL;
}
return shm;
}
void shm_write(shm_t *shm, void *data)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("write");
return;
}
memcpy(shm_data, data, shm->size);
shmdt(shm_data);
}
void shm_read(void *data, shm_t *shm)
{
void *shm_data;
if ((shm_data = shmat(shm->id, NULL, 0)) == (void *) -1)
{
perror("read");
return;
}
memcpy(data, shm_data, shm->size);
shmdt(shm_data);
}
void shm_del(shm_t *shm)
{
shmctl(shm->id, IPC_RMID, 0);
free(shm);
}
int main()
{
int var = 1;
shm_t *shm = shm_new(sizeof var);
int pid;
if ((pid = fork()) == 0)
{ /* child */
var = 5;
shm_write(shm, &var);
printf("child: %d\n", var);
return 0;
}
/* Wait for child to return */
int status;
while (wait(&status) != pid);
/* */
shm_read(&var, shm);
/* Parent is updated by child */
printf("parent: %d\n", var);
shm_del(shm);
return 0;
}
Build with:
$ gcc shm.c -o shm && ./shm
I am trying to have a multithread program that work with struct and semaphore.
I am not sure how to pass those values. Therefore I decided to pass my struct by reference and put my semaphore as a global variable.
What I am trying to do is to make two threads count to 20
(where one would be t1 = 0, 2 , 4 ,6 ... 20 and t2 = 1, 3 , ... , 19)
Here is what I have so far:
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define SEM_sem;
#define MaxVal 20;
typedef struct {
int startVal;
int maxVal;
} countStruct;
sem_t *sem;
void *t1(void *param) {
countStruct *counting;
counting = (countStruct *) param;
int i = counting->startVal;
while(i <= counting->maxVal) {
printf("%d\n",i);
i = i + 2;
sem_post(sem);
sem_wait(sem);
}
pthread_exit(0);
}
void *t2(void *param) {
countStruct *counting;
counting = (countStruct *) param;
int i = counting->startVal;
while(i <= counting->maxVal) {
printf("%d\n",i);
i = i + 2;
sem_post(sem);
sem_wait(sem);
}
pthread_exit(0);
}
int main() {
sem = sem_open(SEM_sem, O_CREAT | O_EXCL, 0666, 0);
if (sem == SEM_FAILED) {
printf("sem_open() failed\n");
sem_unlink(SEM_mpoulinl);
return(8);
}
pthread_attr_t attr;
pthread_t tid1, tid2
countStruct array_struct[3];
int i = 0;
for(i ; i < 2 ; i++) {
array_struct[i].startVal = i;
array_struct[i].maxVal = MaxVal;
}
pthread_create(&tid1, NULL, t1, (void*)&array_struct[0]);
sleep(1);
pthread_create(&tid2, NULL, t=2, (void*)&array_struct[1]);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_close(sem);
sem_unlink(SEM_mpoulinl);
return(0);
}
Unfortunately my code print t1 then t2.
Why is it not working?
is it because my semaphore is global?
I tested taking out sem_post(sem) sem_wait(sem) and the code still work, therefore those two things does not seem to work or am I not using it appropriately?
Thank you!
I'm trying to make a program where a thread writes an integer into a shared memory location and then the other thread reads and prints that integer. the problem I'm facing is that the second thread keeps reading the integer as -1.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
struct args {
void* memptr;
sem_t* semptr;
};
void *p1(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
//sem_wait(semaphore);
//sleep(0.5);
for(int i=0; i<=10; i++)
{
if (!sem_wait(semaphore)) {
printf("got in if p1\n");
sprintf(memory, "%d", i);
sem_post(semaphore);
sleep(1);
}
}
if (!sem_wait(semaphore)) {
sprintf(memory, "%d", 0);
sem_post(semaphore);
sleep(1);
}
sleep(0.1);
}
void *p2(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
sleep(0.1);
while(1)
{
if (!sem_wait(semaphore)) {
printf("got in if p2\n");
if((int)memory == 0){
break;
}
printf("%d\n", (int)memory);
sem_post(semaphore);
sleep(1);
}
}
}
const int ByteSize = 4;
const char* SharedName = "memNameTest";
const char* SemaphoreName = "semNameTest";
int main()
{
int fd = shm_open(SharedName, O_RDWR, 0644);
ftruncate(fd, ByteSize);
void* memptr = mmap(0, ByteSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sem_t* semptr = sem_open(SemaphoreName, O_CREAT, 0644, 0);
sem_post(semptr);
struct args *Share = (struct args *)malloc(sizeof(struct args));
Share->memptr = memptr;
Share->semptr = semptr;
pthread_t thread1, thread2;
printf("Before Thread\n");
pthread_create(&thread1, NULL, p1, (void*)Share);
pthread_create(&thread2, NULL, p2, (void*)Share);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("After Thread\n");
munmap(memptr, ByteSize);
close(fd);
sem_close(semptr);
unlink(SharedName);
return 0;
exit(0);
}
I have tried changing (int)memory into *((int*)memory) but that resulted in a segmentation error.
(edit)
as suggested I tried this in a single-threaded program and got it to work as follows:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
/* the size (in bytes) of shared memory object */
const int SIZE = 4;
/* name of the shared memory object */
const char* SharedName = "memoryInt";
/* create the shared memory object */
int shm_fd = shm_open(SharedName, O_CREAT | O_RDWR, 0644);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
void* memptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=1; i<=10; i++){
/* write to the shared memory object */
//sprintf(memptr, "%d", i);
memcpy(memptr, &i, sizeof(int));
printf("%d\n", *((int*)memptr));
sleep(1);
}
return 0;
}
though this still doesn't work in a multi-threaded program as i get a segmentation fault.
this is the output:
Before Thread
got in if p1
Segmentation fault
First, you have to show what happen on your terminal when you compile your program.
Secondly, the function sprintf has the declaration:
sprintf(char *str, const char *format, ...);
That means the p1 will write the null terminated string of character. In your code, i dont understand why you use the void pointer memory instead of using char pointer as the description. You should verify the read/write function by using single-threaded before applying to the multi-thread.
I am working on a program that stores the variable Bank in shared memory and causes a race condition. My code compiles but it only prints the initial balance statements and not the resulting balance. Essentially, the program should be printing a balance other than 200 with the race condition and when the condition is fixed using semaphores, it should use different numbers to always print a balance of 200. What am I missing that could cause my program to get caught up after the first printf?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <semaphore.h>
#include <string.h>
//sem_t mutex; // semaphore global variable
struct {
int balance[2];
}
Bank = {{100, 100}};
//struct Bank *bank;
// routine for thread execution
void* MakeTransactions() {
key_t shmkey;
int shmid, seqid;
int seqnum = 5858;
int i, j, tmp1, tmp2, rint;
int *shmint1, *shmint2;
double dummy;
if ((shmkey=ftok(getenv("HOME"), seqnum))==(key_t)-1) {
perror("ERROR: ftok");
}
else if ((shmid=shmget(shmkey,sizeof(int)*2,0600|IPC_CREAT))==-1) {
perror("ERROR: shmget");
}
if ((shmint1=(int *)shmat(shmid,NULL,0600))==(int*)-1) {
perror("ERROR: shmalloc");
}
shmint2 = shmint1 + 1;
// wait on semaphore
//sem_wait(&mutex);
for (i=0; i < 100; i++) {
rint = (rand()%30)-15;
if (((tmp1= *shmint1)+rint) >=0 &&
((tmp2= *shmint2)-rint)>=0) {
//sem_wait(&mutex);
//bank->balance[0] = tmp1 + rint;
*shmint1 = tmp1 + rint;
//sem_post(&mutex);
usleep(5000);
for (j=0; j < rint*100; j++) {
dummy=2.345*8.765/1.234; // spend time on purpose
}
//sem_wait(&mutex);
//bank->balance[1] = tmp2 - rint;
*shmint2 = tmp2 - rint;
//sem_post(&mutex);
}
}
Bank.balance[0]= *shmint1;
Bank.balance[1]= *shmint2;
// increment value of semaphore
//sem_post(&mutex);
return NULL;
}
vint main(int argc, char **argv) {
key_t shmkey;
int shmid, seqid, seqnum;
int *shmint1, *shmint2;
int i;
// initialize semaphore
//sem_init(&mutex, 0, 1);
// shared memory
//bank = mmap(NULL, sizeof(struct Bank), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if ((shmkey=ftok(getenv("HOME"), seqnum))==(key_t)-1) {
perror("ERROR: ftok");
}
else if ((shmid=shmget(shmkey,sizeof(int)*2,0600|IPC_CREAT))==-1) {
perror("ERROR: shmget");
}
if ((shmint1=(int *)shmat(shmid,NULL,0600))==(int*)-1) {
perror("ERROR: shmalloc");
}
shmint2 = shmint1 + 1;
memset((int*)shmint1,0,sizeof(int));
memset((int*)shmint2,0,sizeof(int));
/*//check if bank is not NULL
Bank.balance[0] = 100;
Bank.balance[1] = 100;
*/
*shmint1 = Bank.balance[0];
*shmint2 = Bank.balance[1];
pid_t pid;
srand(getpid());
printf("\nInit balances A:%d + B:%d ==> %d!\n",*shmint1,*shmint2,*shmint1 + *shmint2);
pid=fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid == 0) {
MakeTransactions();
return 0;
}
else {
MakeTransactions();
wait(NULL);
return 0;
}
printf("Let's check the balances A:%d + B:%d ==> %d ?= 200\n\n",*shmint1,*shmint2,*shmint1 + *shmint2);
//sem_destroy(&mutex);
// deattach shared memory pointer
shmdt(shmint1);
shmctl(shmid, IPC_RMID, NULL);
// memory unmap struct
//munmap(bank, sizeof(struct Bank));
return 0;
}
The wait() method you're using, as it is described here, looks like it may result in undefined behaviour when parsing NULL; it uses the integer pointer as an indicator of process completion.
I am learning some simple producer/consumer examples involving semaphores, but having a hard time explaining to myself why I am getting a certain result (because I am a noobie to C).
When I run two concurrent processes of the following producer, both processes get hung up and never finish:
#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#define BUFF_SIZE 20
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
shared_data *shm, *s;
char sem_name1[] = "mutex";
char sem_name2[] = "empty_slots";
char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
void Put(char item)
{
sem_wait(empty_slots);
sem_wait(mutex);
s->buffer[s->nextIn] = item;
s->nextIn = (s->nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ... with pid = %d\n", item, getpid());
sem_post(full_slots);
}
void Producer()
{
int i;
for(i = 0; i < 10; i++)
{
sleep(rand()%3);
Put((char)('A'+ i % 26));
}
}
void main()
{
//Create and initialize the semaphores
mutex=sem_open(sem_name1, O_CREAT,0644, 1);
full_slots=sem_open(sem_name3, O_CREAT,0644, 0);
empty_slots=sem_open(sem_name2, O_CREAT,0644, 10);
//Create a key for the segment
key_t key;
key = 1234;
//create the segment
int shmid;
if ((shmid = shmget(key, sizeof(shared_data), IPC_CREAT |0666)) <0)
{
perror("Shmget");
exit(1);
}
//attach to the segment
if ((shm = (shared_data *) shmat(shmid, NULL, 0))==(shared_data *) -1)
{
perror("Shmat");
exit(1);
}
s=shm;
s->nextIn = 0;
Producer();
//detach from the segment
shmdt((void *) shm);
}
The output from the first and second processes, respectively:
Can someone help me understand why this happens (i.e. why do these processes never finish)? Have I created a deadlock? Why or why not? I am completely stumped.
Thanks!