I'm trying to implement a program similar to this example:
the program passes an integer among 4 processes and each process decrements the integer
each process have its own mailbox
Each process check its mailbox for variable "counter" and if it was found it will decrements it
Then it send the counter variable to the next process
but there is a bug in the program and I cant find it.
note that this an assignment and Im just looking for tips that helps me find the bug.
typedef struct {
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
int main(int arqc, char *argv[]){
int key=9;
int id=0;
pid_t pid;
int num=5;
int i, k;
int arr[5];
//create 5 forks
if (arqc != 2){
num=5;
}else{
int ret = sscanf(argv[1], "%d", &num);
if (ret != 1)return 0;
}
for(i=0 ; i<num ; i++){
if ((pid = fork()) == -1) {
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
if (pid == 0) {
id=i;
}
else {
break;
}
}
//process 1 to n comes here
msg m;
int boxid = msgget(id, 0600 | IPC_CREAT);
arr[id]=boxid;
int firstRun=1;
//initiate the first move
if((id==0)&&(firstRun==1)){
m.counter = INIT_COUNTER;
//send msg to next process
msgsnd(arr[id], &m, sizeof(msg), 0); //send msg to own inbox
firstRun=0;
}
while(1){
//check inbox of current process
int rec = msgrcv(arr[id], &m, sizeof(msg), 0, 0);
printf("Im %d, counter is %d, rec is %d\n",id, m.counter, rec);
int index;
if(id==num){
index=0;
}else{
index=id+1;
}
//send message to the next inbox
int sent = msgsnd(arr[index], &m, sizeof(m), 0);
printf( "Error opening file: %s\n", strerror( errno ) );
sleep(1);
}
}
Your initial msgsnd is failing with an invalid argument and everything get munged from there on.
SysV message queues require a message type field as the first field in a message so you need to do something like this.
typedef struct
{
long int mtype;
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
You also have to set the message to something and set the correct length before you send it.
//initiate the first move
if ((id == 0) && (firstRun == 1))
{
m.mtype = 100;
m.counter = INIT_COUNTER;
strncpy(m.data, "some kind of message is nice", sizeof(m.data));
m.id = id;
size_t msgsize = sizeof(msg) - sizeof(long int);
//send msg to next process
int sent = msgsnd(arr[id], &m, msgsize, 0); //send msg to own inbox
if (sent == -1)
{
perror("msgsend");
exit(1);
}
firstRun = 0;
}
You run into problems beyond this (e.g. set the correct size on the msgrcvs) but this should get you over the initial hump.
First of all, it is unreasonable to expect the SO crowd to just solve the (homework?) problem for you without any effort on your side. It is unclear what the problem is, how the program behaves currently, and what steps were made to debug it.
Rants aside, I'd recommend cutting out all the steps leaving only two participants and getting it to work in that simple configuration. Once it works, add another one, make sure it still works and so on.
Related
I am learning how to use threads in C and have run into a problem when creating the threads. I am making a program that takes in 2 or more file names as command line arguments, counts the number of bytes in each file in their own thread, and then outputs the name of the largest file. When I use pthread_join() directly after creating a thread, the program runs as intended. However, I know this isn't how threads should be used because it defeats the purpose. When I use pthread_join() in a for loop after creating all the threads, then the program does not work correctly. Could anyone tell me what I am doing wrong? All help is appreciated. Here is my main function.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //mutex for changing max_bytes and max_name
int max_bytes = 0;
char max_name[100];
struct arg_struct{ //struct to hold args to pass the threads
int fd;
char name[100];
};
int main(int argc, char* argv[])
{
if(argc < 3){ //checks for correct number of arguments passed
perror("Wrong number of arguments");
return EXIT_FAILURE;
}
int arg_num = argc - 1; //holds number of arguments passed
pthread_t threadid[arg_num]; //array of thread IDs
struct arg_struct args;
for(int i = 0; i < arg_num; i++){
args.fd = open(argv[i+1], O_RDONLY);
memcpy(args.name, argv[i+1], sizeof(args.name)); //copies file name into arg_struct
int thread_err = pthread_create(&threadid[i], NULL, count_bytes, (void*)&args); //create thread by calling count_bytes and passing it a struct of args
//pthread_join(threadid[i], NULL);
if(thread_err != 0){
perror("pthread_create failed");
return EXIT_FAILURE;
}
}
for(int i = 0; i < arg_num; i++){
pthread_join(threadid[i], NULL);
}
printf("%s is the largest of the submitted files\n", max_name);
return 0;
}
This is the function that the threads are running.
void *count_bytes(void* arguments)
{
struct arg_struct *args = (struct arg_struct*)arguments; //casting arguments back to struct from void*
int fd = args -> fd;
char name[100];
memcpy(name, args -> name, sizeof(name)); //copies file name into name from args.name
int bytes = 0;
int size = 10;
char* buffer = (char*) malloc(size);
if(buffer == NULL){
perror("malloc failed");
exit(EXIT_FAILURE);
}
int buffer_count = 0;
for(int i = 0; i < size; i++){
buffer[i] = '\0'; //sets all elements to '\0' to determine end of file later
}
int read_return = read(fd, &buffer[buffer_count], 1);
if(read_return == -1){
perror("reading failed");
exit(EXIT_FAILURE);
}
while(buffer[buffer_count] != '\0'){
bytes++;
buffer_count++;
buffer[buffer_count] = '\0'; //sets previous element to '\0' to determine end of file later
if(buffer_count >= size){
buffer_count = 0; //buffer will hold up to 10 elements and then go back to the beginning
}
read_return = read(fd, &buffer[buffer_count], 1);
if(read_return == -1){
perror("reading failed");
exit(EXIT_FAILURE);
}
}
printf("%s has %d bytes\n", name, bytes);
pthread_mutex_lock(&mutex);
if(bytes > max_bytes){
max_bytes = bytes;
memcpy(max_name, name, sizeof(max_name));
}
//locks mutex to avoid race condition
//then sets bytes to max_bytes if it is later than max_bytes
//then locks mutex to allow another thread to have access
pthread_mutex_unlock(&mutex);
return NULL;
}
If it is of any use, these are the two outputs produced when it is running correctly
./a.out another buffered_readword.c
another has 8 bytes
buffered_readword.c has 3747 bytes
buffered_readword.c is the largest of the submitted files
And not correctly
./a.out another buffered_readword.c
buffered_readword.c has 1867 bytes
buffered_readword.c has 1881 bytes
buffered_readword.c is the largest of the submitted files
The problem is that there is only one args structure. After pthread_create is called the new thread may not run immediately. By the time the threads run it is likely that they will both see the same args values. Calling pthread_join inside the thread creation loop "fixes" that because it ensures each thread finishes before args is updated to the next value.
To fix properly pass a different args to each thread. Illustrative code to do that:
struct arg_struct args[arg_num];
for(int i = 0; i < arg_num; i++){
args[i].fd = open(argv[i+1], O_RDONLY);
memcpy(args[i].name, argv[i+1], sizeof(args[i].name));
int thread_err = pthread_create(&threadid[i], NULL, count_bytes, &args[i]);
....
What should I modify in the below codes in order to use only one message queue for one server and
multiple clients. I'm pretty sure I need to assign different values to msgid and then use that to fetch the messages from the message queue but not completely sure if I'm right and how to implement it. I would be grateful for any help.
Code1:
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};
int main() {
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, “msgget failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1) {
fprintf(stderr, “msgrcv failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}
printf(“You wrote: %s”, some_data.some_text);
if (strncmp(some_data.some_text, “end”, 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, “msgctl(IPC_RMID) failed\n”);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Code 2:
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type; char some_text[MAX_TEXT];
};
int main() {
int running = 1;
struct my_msg_st some_data; int msgid;
char buffer[BUFSIZ];
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, “msgget failed with error: %d\n”, errno);
exit(EXIT_FAILURE);
}
while(running) {
printf(“Enter some text: “);
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, “msgsnd failed\n”);
exit(EXIT_FAILURE);
}
if (strncmp(buffer, “end”, 3) == 0) {
running = 0;
}
}
exit(EXIT_SUCCESS);
}
I suggest that you create a single queue and each message that you push to the queue should have a different value for my_msg_type instead of hard coding it to 1 as you have done. This is the mapping between the client and server. Each client can be numbered from 1 till n.
some_data.my_msg_type = client_id;
Once this is done in each client you can call msgrcv with its corresponding client ID. This can be done by using the client ID as the 4th argument in msgrcv.
msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, client_id)
This way you have a single server generating data for multiple clients.
Hope that helps!
I have created a msq to let two processes communicate to one another. The problem is that I'm having some issues since after a couple of time that I run my code some of the old messages of the previous executions show up. This bothers me because I need to perform controls on the current data and cant do it because of this. I tried irpcm -q msqid but it does not do anything except shutting down my program the next time I run it. I even tried hardcoding some keys thinking that it would help but nothing. Also tried to msgctl(msqid, IPC_RMID, 0) after I finished using the queue but nothing. Hope you can help me out and thanks in advance.
Here is my code:
sender.c
#define MAXSIZE 1024
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
void die(char *s)
{
perror(s);
exit(1);
}
int msqid1;
int msgflg = IPC_CREAT | 0666;
key_t keymq1;
struct msgbuf sbuf;
size_t buflen;
keymq1 = 668;
sbuf.mtype = 1;
if ((msqid1 = msgget(keymq1, msgflg )) < 0)
die("msgget");
sbuf.mtype = 1;
strcpy(sbuf.mtext,"my message");
buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid1, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %ld, %s, %zu\n", msqid1, sbuf.mtype, sbuf.mtext, buflen);
die("msgsnd");
}
else {
printf("Message sent\n");
}
receiver.c
#define MAXSIZE 1024
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
void die(char *s)
{
perror(s);
exit(1);
}
int msqid;
key_t keymq1;
struct msgbuf rcvbuffer;
keymq1 = 668;
if ((msqid = msgget(keymq1, 0666)) < 0)
die("msgget()");
if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
die("msgrcv");
printf("Message received: %s\n", rcvbuffer.mtext);
To delete message queue with message queue Id use
ipcrm -q id
or delete the message queue using key value as
ipcrm -Q key_num
From man page "In order to delete such objects, you must be superuser, or the cre‐
ator or owner of the object."
Finally you can delete the message queue using IPC_RMID flag in msgctl() call as
main()
{
int total_mq,i,msqid;
struct msqid_ds ds; //dataStructure holding complete info for indexed message que
struct msginfo msginfo; //general buff copying data from MSG_INFO, has info of how many message que present right now
/* Obtain size of kernel 'entries' array */
total_mq = msgctl(0, MSG_INFO, (struct msqid_ds *) &msginfo); //copy kernel MSGQ_INFO to local buff
//returns count of active message Q
if (total_mq < 0)
{
perror("msgctl");
return 0;
}
printf("no of active message queue(KEY) : %d\n", total_mq+1);
/* Retrieve meaasge Queue id's */
for (i = 0; i <= total_mq; i++)
{
msqid = msgctl(i, MSG_STAT, &ds); //from each index using MSG_STAT -> ds, return msgqid
if (msqid <0 )
{
perror("msgctl");
return 0;
}
/* using msgqid remove the message queue */
if ( msgctl(msqid,IPC_RMID,0) < 0 )
{
perror("msgctl");
return 0;
}
}
printf("all message queues removed\n");
return 0;
}
before running above code, create some message queues and then delete those.
I am trying to develop a simple message queue in C but I am running towards some frustrating problems. I have a number of 10 processes that are divided in two groups of five. Each of the processes of this group must speak with only one of the processes of the other group, and to do that I have assigned different keys to the message queue creation (sorry if it is not the best idea but i'm new to C and trying to adapt). My main issue though is that when I run the code the first time if tells me that 'No such file or directory exists" as a mq error. When I run it from this point on the server receives the message just fine, but it receives the 'old' messages, which are the ones that the client has sent the prior execution. I've been trying to look for what to change but haven't come up with anything. This is my code:
server.c
int keys[] = {1111, 1112, 1113, 1114, 1115};
int msqid;
key_t keymq1;
struct msgbuf rcvbuffer;
keymq1 = keys[indiceProcesso];
if ((msqid = msgget(keymq1, 0666)) < 0)
die("msgget()");
if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
die("msgrcv");
printf("Messaggio ricevuto da A con pid %d: %s\n",getpid(), rcvbuffer.mtext);
client.c
int msqid1;
int msgflg = IPC_CREAT | 0666;
key_t keymq1;
struct msgbuf sbuf;
size_t buflen;
keymq1 = keys[indiceProcesso];
sbuf.mtype = 1;
if ((msqid1 = msgget(keymq1, msgflg )) < 0)
die("msgget");
sbuf.mtype = 1;
strcpy(sbuf.mtext,"My message");
buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid1, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %ld, %s, %zu\n", msqid1, sbuf.mtype, sbuf.mtext, buflen);
die("msgsnd");
}
else
printf("Message Sent\n");
Hope you can help me out and thank you for your time.
I'm trying to control a process using a timer. (Just trying to see how it works in order to implement it in another program. The purpose of that program is to call a function in a specific interval. But when I did that, it turned out that it was using too much CPU. I'm also trying to avoid using sleep.I got the timer to work, what it was implemented in a while loop, so it was hogging all of the CPU.
What I want is for the timer_handler to unlock the thread so that it can proceed with the rest of the program, and also for it to perform the same exact action at precise intervals.
This is the code that I have so far
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
int set_count = 0;
static int count = 0;
int timer_set();
sem_t sem;
struct inits{
struct sigaction sa;
struct itimerval timer;
}inits[1];
int timer_handler (int signum)
{
printf ("timer expired %d times\n", ++count);
if(sem_post(&sem)== -1){
write(STDERR_FILENO, "sem_post() failed \n", 18);
_exit(EXIT_FAILURE);
return 0;
}
else
return 0;
}
int timer_set(){
memset (&inits[0].sa, 0, sizeof (inits[0].sa));
inits[0].sa.sa_handler = timer_handler;
sigemptyset(&inits[0].sa.sa_mask);
inits[0].sa.sa_flags = 0;
printf("sigaction successfull: \n");
/* Configure the timer to expire after 1000 msec... */
inits[0].timer.it_value.tv_sec = 1;
inits[0].timer.it_value.tv_usec = 0;
/* ... and every 1000 msec after that. */
inits[0].timer.it_interval.tv_sec = 1;
inits[0].timer.it_interval.tv_usec = 0;
/* Start a virtual timer. It counts down whenever this process is
executing. */
if(setitimer (ITIMER_VIRTUAL, &inits[0].timer, NULL) == -1)
handle_error("timer set failed: ");
printf("timerset successful\n");
return 0;
}
int main ()
{
int s = 1;
int j;
int* sval;
printf("S value = %d\n", s);
// scanf("\n%d", &set_count);
if (sem_init(&sem, 1, 1) == -1)
handle_error("sem_init");
else{
printf("sem_init successful\n");
printf("sem_init has been set s = %d\n", s);
}
printf("j = %d\n", j=timer_set());
/* Do busy work. */
while (1)
{
sem_getvalue(&sem, sval);
if (errno==EINVAL)
handle_error("Error returned on sem_getvalue: ");
printf("entered while loop\n, S = %d\n", *sval);
while ((s= sem_wait (&sem))==0 && errno == EINTR)
{
printf("entered while loop, S = %d\n", *sval);
printf("entered sem while loop\n");
continue;
}
if (s == -1)
handle_error("Semaphore Wait failed\n");
else
printf("Semaphore Successful\n");
}
printf("thank you for using this timer. ADIOS!\n");
exit(1);
}
The problem is that it doesn't go through the second loop of while, and freezes.
Sorry I haven't yet figured out how to post proper code, so I apologize if it looks weird. .
Also, I've been researching this for a while now so I apologize if there's something that I have missed in my research which may or may not have answered my question.
Thanks in advance