Writing in System V shared memory segment - c

I'm studying shared memory and now I'm writing a program that use system v shared memory. This is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
#define PG_SIZE sysconf(_SC_PAGESIZE)
#define PROJ_ID 1
#define SHM_FILE "/dev/shm/myshm"
void executeChild( void );
void executeParent( void );
int main ( int argc, char *argv[] )
{
unlink(SHM_FILE);
int fd = creat(SHM_FILE, S_IRWXU );
if( fd == -1 ){
perror("Segment memory file creation failed");
exit(1);
}
int pid = fork();
if( pid < 0){
perror("Fork failed\n");
return EXIT_FAILURE;
}
if( pid ){
executeParent();
printf("Parent waiting...\n");
int status = 0;
wait(&status); //wait for child process
printf("Parent done\n");
}else{
executeChild();
}
close( fd );
return EXIT_SUCCESS;
}
void executeChild( void )
{
printf("Child running\n");
sleep(15);
}
void executeParent( void )
{
printf("Parent running\n");
key_t token = ftok(SHM_FILE, PROJ_ID);
if( token == -1 ){
perror("Token creation failed");
exit(1);
}
int segment = shmget( token, PG_SIZE, IPC_CREAT | IPC_EXCL | S_IRWXU);
if ( segment == -1 ){
perror("Segment creation failed");
exit(1);
}
void * shm_ptr = shmat(segment, NULL, 0);
if( shm_ptr == (void *)(-1) ){
perror("Segment attachament failed");
exit(1);
}
printf("Shared memory ( %d ) attached\n", segment);
struct shmid_ds shm_info;
if( shmctl(segment, IPC_STAT, &shm_info) == -1 ){
perror("shmctl failed");
exit(1);
}
printf("Segment size = %zu\n", shm_info.shm_segsz);
printf("Writing...\n");
const char * test = "teste";
memcpy(shm_ptr, test, strlen(teste));
}
The file of the shared memory is created. I can see it on /dev/shm and icps commando also show it. But the size of the file of my shared memory segment is not increasing. So I presume that the memcpy is not working properly like I was expected. Why?

Finally, I got it how shared memory really works... special thanks for Thiago Klock.
The file passed to ftok does not change its size. It exists just for generate the unique key used in the Interprocess Communication... :)
This is my source code where my parent process write a simple message to the child process:
https://github.com/guilhermesft/vanzstuff/blob/master/ipc/shmsysv.c

Related

Semaphore and alternating printing

I want the following: first the parent process prints "hello", then the child process prints "world" and this is done 3 times. When I execute my code I only get hello world once but I want to get it printed 3 times.
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char*argv[]){
char* parent="hello ";
char* child="world";
sem_t *sem = sem_open("/mysem", O_CREAT, 0644, 1);
sem_t *sem1=sem_open("/mysem1", O_CREAT, 0644, 0);
int pid=fork();
if(pid<0){
printf("error in forking");
return -1;
}
int cnt=0, cnt1=0;
if(pid==0){
sem_wait(sem1);
write(1, child, strlen(child));
cnt++;
if(cnt1<3){
sem_post(sem);
}
}else{
sem_wait(sem);
write(1, parent, strlen(parent));
cnt++;
if(cnt<3){
sem_post(sem1);
}
}
return 0;
}
maybe try this :
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#define BUFFER_SIZE 7
int main(int argc, char **argv)
{
char parent[BUFFER_SIZE] = "hello ";
char child[BUFFER_SIZE] = "world\n";
sem_t *sem = sem_open("/mysem", O_CREAT, 0644, 1);
sem_t *sem1 = sem_open("/mysem1", O_CREAT, 0644, 0);
int cnt = 0;
int pid = fork();
if (sem == SEM_FAILED || sem1 == SEM_FAILED) {
printf("Error : sem_open() call failed.\n");
return (-1);
}
if (pid < 0) {
printf("error in forking");
return (-1);
}
if (pid == 0) {
while (cnt < 3) {
sem_wait(sem1);
if (write(1, child, strlen(child)) == -1) {
printf("Error : write call failed.\n");
}
cnt++;
sem_post(sem);
}
}
else {
while (cnt < 3) {
sem_wait(sem);
if (write(1, parent, strlen(parent)) == -1) {
printf("Error : write function failed.\n");
}
cnt++;
sem_post(sem1);
}
}
sem_close(sem);
sem_close(sem1);
return (0);
}
Explanation :
#define BUFFER_SIZE 7 this is a macro, 7 because of part 2.
Memory leaks (use valgrind)
Don't do : char *str = "abc";
but do : char str[string_size + 1] = "abc";
Because char *str = doesn't allocate memory so you will probably get memory leaks, always allocate string_size + 1 with C String. You can use malloc too to allocate your own size.
Put your int cnt variables before the fork(), fork will copy all memory so you can put only one variable before your fork call, for more readable code.
You should always call sem_close() as soon as possible and you should always look for returned value from functions that are not your, use C man, for exmaple "man 2 write" in your linux console (not looking for sem_wait semp_post and sem_close returned value shouldn't be problematic here, but you can still print a message if you want).
Your main problem here is that you should switch your if (cnt < 3) into a loop as i did with while, your parent and child process only course once write() if you don't set a loop.
The most important thing, please look for coding style rules to make your code more redeable.
This is pretty long, but you should take at look in all i said.
Compilation :
gcc file.c -pthread
./a.out
I'm on linux, fedora32.
Output :
hello world
hello world
hello world

Sending information with unnamed pipes

My program have to send some bytes of information by using unnamed pipes.
I have a txt file named "input" which is supposed to be read by the program and it's information have to be send and write in another file named "output". Also i must use read(), write(), open() functions.
My code look like this:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#define BUFSIZE 25
int main( int argc, char *argv[] ) {
srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;
ret = pipe(mypipefd);
if( ret == -1 ) {
perror( "pipe error");
exit(1);
}
pid = fork();
if( pid == -1 ) {
perror( "FORK ERROR...");
exit(2);
}
if( pid == 0 ) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(3);
}
while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) {
sleep(rand() %2);
write(mypipefd[1], buf, nbytes );
}
if ( close(stream) == -1 ) {
perror("ERROR CLOSING STREAM");
exit(4);
}
}
else {
/* PARENT */
printf(" Parent process...\n");
output = open("output.txt", O_CREAT | O_WRONLY, 00777);
while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) {
write(output, buf, nbytes);
}
printf("buf: %s\n", buf);
if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
}
return 0;
}
Unfortunately the code is not working terminal screen
Before I tried while loop and was sending all the information at once, it worked, but output file looked like this output file
while the input file look like this input file
The primary bug was that the parent must do close(mypipefd[1]) before the parent read loop (and not after). This prevented the parent from seeing EOF on the pipe after the child was done writing.
Also, you were missing a waitpid in the parent.
The printf for buf in the parent was in the wrong place [after the read loop]. At that point, buf can't be guaranteed to have the correct data or that it's correctly zero-terminated. That's why stdout had some garbage chars at the end.
So, In addition to outputting to the output file, the loop should output to stdout, but should use fwrite as buf can't be guaranteed to be zero terminated.
I had missed that in my initial post, so I've corrected it.
As per my top comments, the child should loop on a [possible] partial write to the pipe. I coded that.
Here's the version with the bugs annotated and fixed:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 25
int main( int argc, char *argv[] ) {
srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;
ret = pipe(mypipefd);
if( ret == -1 ) {
perror( "pipe error");
exit(1);
}
pid = fork();
if( pid == -1 ) {
perror( "FORK ERROR...");
exit(2);
}
if( pid == 0 ) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(3);
}
while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) {
sleep(rand() %2);
#if 0
write(mypipefd[1], buf, nbytes );
#else
// NOTE: this _should_ work but adds extra at the end
int off;
int wlen;
for (off = 0; nbytes > 0; off += wlen, nbytes -= wlen) {
wlen = write(mypipefd[1], buf + off, nbytes );
if (wlen <= 0)
break;
}
#endif
}
if ( close(stream) == -1 ) {
perror("ERROR CLOSING STREAM");
exit(4);
}
// NOTE/FIX: child must close it's side of the pipe
#if 1
close(mypipefd[1]);
#endif
}
else {
/* PARENT */
printf(" Parent process...\n");
// NOTE/FIX: this must be closed _before_ the read loop -- holding it
// open prevents parent from seeing EOF on pipe
#if 1
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
#endif
#if 1
printf("buf: ");
#endif
output = open("output.txt", O_CREAT | O_WRONLY, 00777);
while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) {
write(output, buf, nbytes);
#if 1
fwrite(buf,1,nbytes,stdout);
#endif
}
// NOTE/BUG: the buffer at this point will only have the data from
// the _last_ read and may not be null terminated
#if 0
printf("buf: %s\n", buf);
#else
printf("\n");
#endif
if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}
// NOTE/BUG: this must be closed _before_ the parent's read loop
#if 0
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
#endif
// NOTE/FIX: this is missing (prevents orphan/zombie child process)
#if 1
waitpid(pid,NULL,0);
#endif
}
return 0;
}
UPDATE:
but i don't understand what does "for" loop do here
A write to a pipe can generate a "short write" (e.g. you want to write 20 but the return value (i.e. number of bytes actually written) comes back with 15. You have to index into the buffer and write the remaining bytes in subsequent writes.
There is a kernel limit on how many bytes can be written in a single atomic write (e.g.) if you did write(mypipefd[1],buf,10000000), the kernel doesn't have space allocated for such a large write, so it will return the value of what it could append to the pipe buffer [in the kernel].
Also, let's say the kernel pipe buffer can hold 64 bytes. And you write buffers of size 64 to it. Maybe the reader is reading only 32 bytes. So, the first write is fine. Then reader reads out 32 bytes. So, the next write to the pipe of 64, there is only space for 32 bytes, so the write will return 32
Program have to display: "buf: This is ra" then "buf: ndom text"
Okay, I've fixed that
At last, I need to implement error handling everywhere.
I've annotated places where I'd add error and handling, along with some things to look for.
Anyway, here's an updated version. I've left in the // NOTE/* comments but removed the #if/#endif pairs to make an easier read.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 25
int
main(int argc, char *argv[])
{
srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;
ret = pipe(mypipefd);
if (ret == -1) {
perror("pipe error");
exit(1);
}
pid = fork();
if (pid == -1) {
perror("FORK ERROR...");
exit(2);
}
if (pid == 0) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1) {
perror("ERROR CLOSING PIPE");
exit(3);
}
while ((nbytes = read(stream, buf, BUFSIZE)) > 0) {
sleep(rand() % 2);
// NOTE/FIX: writing to pipes _can_ generate a _short_ write. that
// is, (e.g.) if the length given to write is 20, the return value
// may be only 15. this means that the remaining 5 bytes must be
// sent in a second/subsequent write
int off;
int wlen;
for (off = 0; nbytes > 0; off += wlen, nbytes -= wlen) {
wlen = write(mypipefd[1], buf + off, nbytes);
if (wlen < 0) {
perror("ERROR WRITING TO FILE");
exit(3);
}
if (wlen == 0)
break;
}
}
if (close(stream) == -1) {
perror("ERROR CLOSING STREAM");
exit(4);
}
// NOTE/FIX: child must close it's side of the pipe
// NOTE/ERRCODE: check error code here
close(mypipefd[1]);
}
else {
/* PARENT */
printf(" Parent process...\n");
// NOTE/FIX: this must be closed _before_ the read loop -- holding it
// open prevents parent from seeing EOF on pipe
if (close(mypipefd[1]) == -1) {
perror("ERROR CLOSING PIPE");
exit(6);
}
// NOTE/ERRCODE: this should be checked for -1 (i.e. output file
// could not be opened for file permission, etc. or other reasons
// similar to those for the file write below)
output = open("output.txt", O_CREAT | O_WRONLY, 00777);
// NOTE/FIX: we read one less than buffer size to allow for adding an
// artificial zero byte at the end
while ((nbytes = read(mypipefd[0], buf, BUFSIZE - 1)) > 0) {
// NOTE/ERRCODE: error handling _could_ be added here but it would
// be rare (e.g. filesystem has an I/O error because it's full or
// marked R/O because of an I/O error on the underlying disk)
write(output, buf, nbytes);
// write partial buffer to stdout
buf[nbytes] = 0;
printf("buf: %s\n",buf);
}
if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}
// NOTE/FIX: this is missing (prevents orphan/zombie child process)
// NOTE/ERRCODE: yes, this _can_ have an error return but here it's
// unlikely because we _know_ that pid is valid
// what can be done is to do:
// int status;
// waitpid(pid,&status,0)
// then process the return code from the child using the W* macros
// provided (e.g. WIFEXITED, WSTATUS) on status
waitpid(pid, NULL, 0);
}
return 0;
}

Working with semaphores and shared memory in C

The program should create 200000 integers and write 2000 to a shared memory. A forked process should read 2000 from shared memory and the parent should write the next 2000 to shared memory.
if i use the code below without sleep, the parent first creates all 200000 integers and then the child reads the same integers from shared memory.
With sleep everything looks good, but we have to use semaphore.
shm.c (parent):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/wait.h>
#define N_DATA 200000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
static struct sembuf semaphore;
char shmidArg[32];
char semidArg[32];
int *shmData;
int i, j;
int status;
char *strsignal(int sig);
pid_t pid;
static int shmid;
static int semid;
char *strsignal(int sig);
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 1;
semaphore.sem_op = op;
semaphore.sem_flg = IPC_NOWAIT;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
/* Ein Shared-Memory-Segment einrichten */
shmid = shmget(IPC_PRIVATE, N_SHARED*sizeof(int), IPC_CREAT | SHM_R | SHM_W);
if (shmid == -1) {
perror("shmid");
exit(1);
}
printf("Shared-Memory-ID: %d\n",shmid);
/* Pointer zu Shared-Memory-Segment erhalten */
shmData = (int *)shmat(shmid,0, 0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
/* Semaphore anlegen */
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | SHM_R | SHM_W);
if (semid < 0) {
perror("semid");
exit(1);
}
printf ("Semaphor-ID : %d\n", semid);
/* Semaphor mit 1 initialisieren */
if (semctl (semid, 0, SETVAL, (int) 1) == -1) {
perror("semctl");
}
snprintf(shmidArg,32, "%d", shmid);
snprintf(semidArg,32, "%d", semid);
/** erstellen des Kindprozesses */
pid = fork();
// Kindprozess
if (pid == 0) {
execlp("./shm_child",shmidArg,semidArg,NULL);
} else if (pid < 0) {
perror("Kindprozess konnte nicht erzeugt werden!");
return 1;
}
// Elternprozess
else {
/** ininitalisieren des Zufallsgenerator durch aktuellen Zeitstempel */
srand48(time(NULL));
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for (j=0; j<N_SHARED; j++) {
shmData[j] = lrand48();
//MSZ
//printf("SHM-->%d-->%d\n",i+1,shmData[i]);
}
// if(i == 0 || i == 2000) {
printf("Parent-->%d-->0-->%d\n",i,shmData[0]);
printf("Parent-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
//sleep(1);
}
}
//MSZ
//sleep(2);
printf("PID: %d\n", pid);
if (waitpid(pid, &status, 0) == -1) {
perror("wait konnte nicht erzeugt werden!");
return 1;
}
if (WIFEXITED(status)) {
printf("Exitcode: %d\n", WEXITSTATUS(status));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
//If process terminaded by a signal
} else if (WIFSIGNALED(status)) {
printf("Signal: %d %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
}
}
shm_child.c (Child):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#define N_DATA 6000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
int i,j;
int *shmData;
static int shmid;
static int semid;
static struct sembuf semaphore;
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 0;
semaphore.sem_op = op;
semaphore.sem_flg = SEM_UNDO;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
shmid = atoi(argv[0]);
semid = atoi(argv[1]);
printf("\nshm_child shared memoryid:%d\n",shmid);
printf("shm_child Semaphoren-ID:%d\n",semid);
/* Pointer auf Shared-Memory erstellen */
shmData = (int *)shmat(shmid,0,0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for(j=0;j<N_SHARED;j++) {
//printf("%d-->%d --> %d\n",i,j+1,shmData[j]);
}
// if(i == 0 || i == 2000) {
printf("child-->%d-->0-->%d\n",i,shmData[0]);
printf("child-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
sleep(1);
}
return 0;
}
Please help us
Thank you guys
Edit: Thank you very much for your answers. I can't mark the right answer because i dont know what its right. But i dont want try anything more. 15 hours are enough
The writer process shall give reader a permission to read, and wait for the reading completion. After that the reader shall give writer a permission to proceed, and wait for writing completion.
This goal cannot be achieved with a single semaphore. You need two, along the lines of:
// parent aka writer
writer_barrier = semaphore(UNLOCKED);
reader_barrier = semaphore(LOCKED);
start_reader();
while(...) {
lock(writer_barrier);
write_data();
unlock(reader_barrier);
}
// child aka reader
while(....)
lock(reader_barrier);
read_data();
unlock(writer_barrier);
}

Why unnamed semaphore doesn't change when used in shared memory?

I have to make 2 processes (server/client) that can access the same shared memory. I send the keys of shared memory via UNIX sockets between the server and the client. Then, I create the shared memory segment, and use unnamed semaphores to sychronize the server/client. As I think, I do everything right, but when I run the client process I can see that the semaphore isn't even initialized!
server.c sample:
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <errno.h>
sem_t *semaphore;
int main(int argc, char **argv){
//...making the connections here
// M is the number of semaphores i will use
key_t key3;
int shmid3;
if ((shmid3 = shmget(key3, M*sizeof(sem_t), 0644 | IPC_CREAT)) == -1) {
perror("shmget3");
exit(1);
}
key3 = htonl(key3);
if (send(s2, (const char*)&key3, 4, 0) == -1) {
perror("send");
exit(1);
}
int i;
semaphore=(sem_t *)shmat(shmid3, (void *) 0, 0);
if (semaphore == (sem_t *)(-1)) perror("shmat");
for(i=0;i<M;i++) if(sem_init(&semaphore[i], 1, 1)!=0) perror("sem_init");
//..do some stuff...
sleep(3);
for(i=0;i<M;i++) sem_destroy( &semaphore[i] );
if (shmdt(semaphore) == -1) {
perror("shmdt");
exit(1);
}
shmctl(shmid3, IPC_RMID, NULL);
//close connection...
}
client.c sample:
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <errno.h>
sem_t *semaphore;
int main(int argc, char **argv){
//...making the connections here
// M is the number of semaphores i will use
key_t key3;
n = recv(s, &key3, 4, 0);
if (n < 0) {
perror("recv");
}
key3 = ntohl(key3);
int shmid3;
if ((shmid3 = shmget(key3, M*sizeof(sem_t), 0644 )) == -1) {
perror("shmget3");
exit(1);
}
semaphore=(sem_t *)shmat(shmid3, (void *) 0, 0);
if (semaphore == (sem_t *)(-1)) perror("shmat");
int value;
sleep(1);
sem_getvalue(&semaphore[0], &value);
printf("\n[%d]\n",value); //always prints 0
//...do stuff...
if (shmdt(semaphore) == -1) {
perror("shmdt");
exit(1);
}
//close connection...
}
There isn't something wrong with the UNIX connection because I share and other memory segments, and they work just fine. I also tried changing the pshared argument of sem_initbut still nothing changes in the client.
I actualy want to use the semaphores in clinet's threads(M), but I see that they do not initialize even in the main process.
(Adapting from troubleshooting in the comments...)
The uninitialized key_t key3 happens to be initialized to the value IPC_PRIVATE, which means that a new shared memory segment is created for each caller of shmget(). The key should be explicitly initialized (in this case as by ftok()).

how the system call read and write behave and why the threads cannot work?

fifo.3 source code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <time.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
#define TEN_MEG (1024 * 1024 * 1)
void* thread_tick(void* arg)
{
int count =0;
while(count < 4){
printf("hello, world!\n");
sleep(1);
count++;
}
}
void* thread_write(void* arg)
{
int pipe_fd;
int res;
int bytes_sent = 0;
char buffer[BUFFER_SIZE ];
int count=0;
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
while(count < 10){
printf("write: Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_WRONLY);
printf("write: Process %d result %d \n", getpid(), pipe_fd);
if (pipe_fd != -1) {
while(bytes_sent < TEN_MEG) {
res = write(pipe_fd, buffer, BUFFER_SIZE);
if (res == -1) {
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("write: Process %d finished , count =%d\n", getpid(),count);
count++;
}
}
void CreateThread(void* (*start_routine)(void*), void* arg,int stacksize, int priority)
{
pthread_t app_thread;
pthread_attr_t thread_attr;
int res;
int max_priority;
int min_priority;
struct sched_param scheduling_value;
res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setstacksize(&thread_attr, stacksize);
if (res != 0) {
perror("Set stack size failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
max_priority = sched_get_priority_max(SCHED_RR);
min_priority = sched_get_priority_min(SCHED_RR);
scheduling_value.sched_priority = priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&app_thread, &thread_attr, (*start_routine), arg);
if(res != 0){
perror("Thread creation failed\n");
exit(EXIT_FAILURE);
}
pthread_attr_destroy(&thread_attr);
//res = pthread_join(app_thread ,0 );
//return app_thread;
}
int main()
{
CreateThread(thread_write, 0, 50000, 99);
CreateThread(thread_tick, 0, 50000, 98);
// pthread_join(w,0 );
// pthread_join(t ,0 );
return 0;
}
fifo.4 source code :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE ];
int bytes_read = 0;
int count = 0;
memset(buffer, '\0', sizeof(buffer));
while(count < 10){
printf("read: Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_RDONLY);
printf("read: Process %d result %d\n", getpid(), pipe_fd);
if (pipe_fd != -1) {
do {
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > 0);
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("read: Process %d finished, %d bytes read , count =%d\n", getpid(), bytes_read,count);
count++;
}
return 0;
}
this is the first time I post code on Stack overflow, so it is in a mess.
Above are two C source code. fifo3.c has two thread and thread_write is to write data to named fifo.
fifo4.c is to read data from named fifo.
my question:
1) how does the read(pipe_fd, buffer, BUFFER_SIZE) behave when write() is writing data to fifo? If read() can not read data, SHOULD not read() return 0 and then exit, why read() would wait write() to finish write data??? of course, how does write() behave when read() is reading?
2) in fifo3.c , I create two threads, when I create them detached , the program can not run !!!
but joinable, they could run correctly !!I do not know why!
In theory, they both could function right.
Answer for Question-1:
If read cannot read data it will 'block' till data arrives, this is called blocking mode read. Incase of a blocking mode read, the read call blocks till a data arrives. If you wish to change it to non-blocking mode, you can use fcntl functionality, if the same is supported.
For other queries, it is best that you read about it through man pages as a concise answer will be difficult.
Answer for Question-2:
When you create a thread detached, it means the created threads are not bound to the parent thread which creates it. So, the parent thread will just exit, if it completes it's work. If the parent happens to be the main thread, then when it exits the process also will exit, which will cause program not to run.

Resources