0

So the program works like this. There is a producer, and 4 consumers. The producer generates 6 random numbers and sends them through message queues into the 4 consumers. Each consumer receives them and, immediately before terminating, should send through another queue one message with mayproduce=0; mayproduce is an integer.

The function in question is:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

I use the function like this to send mayproduce

msgsnd(qid,&mayproduce,sizeof(int),0)

when I compile it says "Invalid argument".

If I change mayproduce to other number, for mayproduce=2, the program works fine.

Does anyone know the reason it doesn't accept 0 as an argument?

A sample of the code:

mayproduce=2; // if I put 0 here it doesn't work
if(msgsnd(msq2,&mayproduce,tamanho,0)<0) {
   perror("\nConsumidor:Erro ao enviar a mensagem: ");
   exit(1);
}
12
  • 1
    Show the full error message. And a full code or a somewhat complete snippet at the very least. Commented May 29, 2017 at 19:52
  • mayproduce==0 is not like "setting mayproduce to another number". It is a comparison which sets mayproduce to 0 or 1. Voting to close for lack of MCVE. Commented May 29, 2017 at 19:53
  • yes it @WeatherVane it was my mistake. I meant mayproduce=0 Commented May 29, 2017 at 20:03
  • Your still need to post the Minimal, Complete, and Verifiable example that shows the problem. Commented May 29, 2017 at 20:05
  • yes my bad. But the code is somewhat complex. Commented May 29, 2017 at 20:11

1 Answer 1

1

The msgsnd() documentation states:

   The msgp argument is a pointer to a caller-defined 
    structure of the following general form:

       struct msgbuf {
           long mtype;       /* message type, must be > 0 */
           char mtext[1];    /* message data */
       };

The manpage has a lot more info that you need to read very, very carefully.

So you are not really supposed to send a pointer to an int. You are supposed to create your own struct, where the 1. member is of type long, and is used as a message type discriminator that the receiver can look at to determine what kind of message it received.

The size you pass to msgsend() is the size of everything you send that comes after the mtype member.

When you perform msgsnd(qid,&mayproduce,sizeof(int),0) the following happens:

  • The mayproduce int is interpreted as the mtype member in a struct msgbuf , as the documentation says, it cannot be 0
  • The sizeof(int) says you will an int in addition to the long msgtype. But your &mayproduce pointer just points to an a single int, thus you are likely also sending over garbage values grabbed from the stack.

You should do something like:

struct MyMsg {
     long mtype;  
     int mayproduce;
};

struct MyMsg msg;
msg.mtype = 1; //or whatever you want > 0
msg.mayproduce = ....; //whatever you want to send.
size_t msgsize = sizeof(struct MyMsg) - sizeof(long);

msgsnd(msq2,&msg,msgsize,0);
Sign up to request clarification or add additional context in comments.

10 Comments

Isn't the calculation of msgsize vulnerable to padding? If (say) long is 8 bytes and int is 4. Then sizeof(struct MyMsg) is likely to by 16 and end padded. There's no guarantee of that but that's typical for an aligned 64-bit architecture. As a result it will calculate msgsize=sizeof(struct MyMsg) - offsetof(struct MyMsg, mayproduce); as 8. Consequently a trap expression will be sent. That's not necessarily harmful if the receiver only looks at the first 4 bytes but isn't msgsize=sizeof(int) the right answer?
@Persixty Why would a trap expression be sent ? We allocated a struct MyMsg, and told msgsnd() to send all 8 bytes starting at mayproduce to the end, including padding, if any. I suspect the size calculation isn't quite correct though, there will be an issue if there's padding between mtype and mayproduce , which will cause an issue when reading into the same struct at the receiving end. The calculation should probably just be sizeof(struct MyMsg) - sizeof(long)
Maybe I'm misusing the term trap expression... I mean (on a 64-bit aligned architecture) will cause 8 bytes to be sent when only 4 are meaningful. It will be fine to copy only 4 bytes into the structure at the other. It doesn't even help if (say) the member type is aligned >long and there's padding before the member because I can't see how msgsend will be able to do anything other than copy sizeof(long)+msgsz around. Safe (but inefficent) code would go with sizeof(struct MyMsg)-sizeof(long) and pass all padding we're assured that mtype is at the start of the struct
@Persixty Yes, we would send 8 bytes, 4 of which would be padding, and that would be no problem, the other end has room for the padding too.
I agree harmless but unnecessarily inefficient. Why not send 4 bytes? Why so keen to copy junk around? If the padding is at the end - ignore it. If the padding were (unusually) betwen the first and second member I don't see how that calculation can work.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.