From: waltbrad on
I'm in a chapter on advanced thread synchronization and the author
uses a queue structure as follows:

typedef struct queue_tag {
HANDLE q_guard; // for a mutex
HANDLE q_ne; // queue not empty
HANDLE q_nf; // queue not full
volatile DWORD q_size; // max queue size
volatile DWORD q_first; // index of oldest msg
volatile DWORD q_last; // index of youngest msg
volatile DWORD q_destroyed; // Q receiver has terminated
PVOID msg_array; // array of q_size messages

} queue_t;

Fine. Then comes this function.

DWORD q_full (queue_t *q)
{
return ((q -> q_first - q -> q_last) ==1 ||
(q -> q_last == q -> q_size - 1 && q -> q_first ==
0));

}

I don't understand the first condition of the return stmt. I
understand the first part of the second condition, but I don't
understand why they had to && it with q_first == 0.

There are two other functions I'm having trouble with the condition.
Both the same condition. It goes:

DWORD q_remove ( queue_t *q, PVOID msg, DWORD msize)
{
char *pm;

pm = (char *)q -> msg_array;
memcpy (msg, pm + (q -> q_first * msize), msize);
q -> q_first = (( q -> q_first +1) % q -> q_size);
return 0;

}

Now in this code I don't understand why they had to use the modulus
expression. What would be wrong with just saying q -> q_first = q -

> q_first + 1;

?

TIA
From: Jim Langston on
waltbrad wrote:
> I'm in a chapter on advanced thread synchronization and the author
> uses a queue structure as follows:
>
> typedef struct queue_tag {
> HANDLE q_guard; // for a mutex
> HANDLE q_ne; // queue not empty
> HANDLE q_nf; // queue not full
> volatile DWORD q_size; // max queue size
> volatile DWORD q_first; // index of oldest msg
> volatile DWORD q_last; // index of youngest msg
> volatile DWORD q_destroyed; // Q receiver has terminated
> PVOID msg_array; // array of q_size messages
>
> } queue_t;
>
> Fine. Then comes this function.
>
> DWORD q_full (queue_t *q)
> {
> return ((q -> q_first - q -> q_last) ==1 ||
> (q -> q_last == q -> q_size - 1 && q -> q_first ==
> 0));
>
> }

I really don't see the code where queue_tag is being used so can only guess
at some of this.

It seems to me that q->q_first - q->q_last would return the number of
elements in your queue minus one. That is, you probably always have a head
and a tail. With an empty queue you would still have 2 elements in it, the
head and the tail. So if the head - tail = 1 then you have no elements in
your queue. Without seeing how it everything is used though I'm just
guessing.

Next we have q->q_last == q->q_size - 1 && q->q_first == 0. Okay, this
seems to be checking if the queue is full. If you have q_size possible
elements, and the first is 0, and the last is size-1 then you are full.

So this seems to be returning true if either there are no elements in the
queue, or there are q_size elements in the queue. Again just guessing on
some of it.

> I don't understand the first condition of the return stmt. I
> understand the first part of the second condition, but I don't
> understand why they had to && it with q_first == 0.
>
> There are two other functions I'm having trouble with the condition.
> Both the same condition. It goes:
>
> DWORD q_remove ( queue_t *q, PVOID msg, DWORD msize)
> {
> char *pm;
>
> pm = (char *)q -> msg_array;
> memcpy (msg, pm + (q -> q_first * msize), msize);
> q -> q_first = (( q -> q_first +1) % q -> q_size);
> return 0;
>
> }
>
> Now in this code I don't understand why they had to use the modulus
> expression. What would be wrong with just saying q -> q_first = q -
>
>> q_first + 1;
>
> ?

Well, usually that would be the case. Consider that q_first is, say, 1.
Say q_size is 10.. (q->first+1)%q->q_size. (1+1)%10 == 2. Which would be
the same as q_first +1. There are conditions where this won't be true
however. What if q->first is 9, 10 or 11?

The code isn't quite clear and we don't see the entire implementation of it,
but it seems to be checking on overflow here in a somewhat tricky manner.



--
Jim Langston
tazmaster(a)rocketmail.com


From: Daniel T. on
In article
<b13a1399-ebfd-4fc7-9e89-e2a5275d19d8(a)e23g2000prf.googlegroups.com>,
waltbrad <waltbrad(a)hotmail.com> wrote:

> I'm in a chapter on advanced thread synchronization and the author
> uses a queue structure as follows:
>
> typedef struct queue_tag {
> HANDLE q_guard; // for a mutex
> HANDLE q_ne; // queue not empty
> HANDLE q_nf; // queue not full
> volatile DWORD q_size; // max queue size
> volatile DWORD q_first; // index of oldest msg
> volatile DWORD q_last; // index of youngest msg
> volatile DWORD q_destroyed; // Q receiver has terminated
> PVOID msg_array; // array of q_size messages
>
> } queue_t;
>
> Fine. Then comes this function.
>
> DWORD q_full (queue_t *q)
> {
> return ((q -> q_first - q -> q_last) ==1 ||
> (q -> q_last == q -> q_size - 1 && q -> q_first ==
> 0));
>
> }

My guess is that this is a circular buffer. if q_first - q_last == 1,
then adding an element would erase the oldest element, i.e., the queue
is full. However, if first - last doesn't equal 1, the queue may still
be full. For example if the last element is at the end (q_last == q_size
- 1) and the first element is at the beginning (q_first == 0) then the
queue is also full.

> I don't understand the first condition of the return stmt. I
> understand the first part of the second condition, but I don't
> understand why they had to && it with q_first == 0.

If q_last was at the end of the buffer, but q_first was at position 1
(for example) then the queue would not be full.

> There are two other functions I'm having trouble with the condition.
> Both the same condition. It goes:
>
> DWORD q_remove ( queue_t *q, PVOID msg, DWORD msize)
> {
> char *pm;
>
> pm = (char *)q -> msg_array;
> memcpy (msg, pm + (q -> q_first * msize), msize);
> q -> q_first = (( q -> q_first +1) % q -> q_size);
> return 0;
>
> }
>
> Now in this code I don't understand why they had to use the modulus
> expression. What would be wrong with just saying q -> q_first = q -
>
> > q_first + 1;

Because if q_first (and q_last) cannot be greater than or equal to
q_size. You can't just add 1 to q_first and be assured it is still
valid. The modulus forces a wrap.