简体   繁体   中英

Minimum of a range in cyclic ints

To give a bit of context, I have n threads receiving ints. These are coming in cycles (let's say we have a uint16, so after 65535 the next received number will be zero again). There is no known mapping from the respective number to the thread it will be received from, like even numbers are received from thread 1 and odd numbers from thread 2 as a simple example. Some threads can also receive more numbers than others (which is actually the reason why the blocking is neccessary) There can be "jumps", meaning the numbers are not received in a strict ascending order. After a number x is received, the next number, be it in the same or another thread, need not be x+1 but can also be less than x or greater than x+1. We can make assumptions about the size of these jumps though (upper bound is N/2 for N being the largest number possible).

To allow the following subsystem to process the numbers correctly we need to make sure they don't drift apart too far when received. The following example should do the trick:

struct thread_status {
    bool block;
    uint16_t last;
}

void *thread_worker(void *data)
{
    struct thread_status *staus = (struct thread_status*)data;

    while (1) {
        if (status->block) {
            if (status->last <= MIN(array_of_lasts_from_all_threads))
                status->block = false;
            else
                continue;
        }

        status->last = receive_next();

        if (status->last >= MIN(array_of_lasts_from_all_threads) + ALLOWED_DIFF)
            status->block = true;
    }
}

Now the actual question is, how would I implement the MIN function? Instead of always comparing to the array of last values, I could also save the minimum last value and just compare to it. Then I need to implement the comparison operator though.

Another example to be more precicse: If I only have ints from 0 to 15 and 3 threads.

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | |X|X| | |0| | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Here, X are the last read values from the other threads and 0 os the currently read value. MIN and comparison are easy here. However in this case

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|X|0| | | | | | | | | | | | | |X|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

the minimum value should be 15 and not zero.

I think you might be asking the wrong question, but it's difficult to explain why. Let's answer the simple question first, and see if it helps you figure out how to implement (or avoid implementing) a MIN function.

If your array boundaries really do lie on a uint16_t boundary, you can find the distance between your 0 read and a given X index with simple subtraction. (Play around with this example a bit to see why.)

uint16_t recent = 1;
uint16_t previous = 65535;
uint16_t foo = (uint16_t)(recent - previous);
printf("%hu\n", foo);

You might think the result would be a uint16_t , but because of the casting rules in C it's probably going to be an int on your platform, thus the explicit cast above. If 0 is after X , this number will be relatively small; if it's the other way around, the number will be close to UINT16_MAX . If you cast to int16_t instead, on most modern platforms you should get a positive or negative number representing both ordering and distance.

If the array boundaries don't lie on a size boundary, you can use modulo arithmetic to "wrap" the subtraction back into a sane region before casting to a signed type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM