Lock Free Queue — Single Producer, Multiple Consumers

前端 未结 4 1212
一生所求
一生所求 2020-12-13 11:06

I am looking for a method to implement lock-free queue data structure that supports single producer, and multiple consumers. I have looked at the classic method by Maged Mic

4条回答
  •  猫巷女王i
    2020-12-13 11:11

    For a traditional one-block circular buffer I think this simply cannot be done safely with atomic operations. You need to do so much in one read. Suppose you have a structure that has this:

    uint8_t* buf;
    unsigned int size; // Actual max. buffer size
    unsigned int length; // Actual stored data length (suppose in write prohibited from being > size)
    unsigned int offset; // Start of current stored data
    

    On a read you need to do the following (this is how I implemented it anyway, you can swap some steps like I'll discuss afterwards):

    1. Check if the read length does not surpass stored length
    2. Check if the offset+read length do not surpass buffer boundaries
    3. Read data out
    4. Increase offset, decrease length

    What should you certainly do synchronised (so atomic) to make this work? Actually combine steps 1 and 4 in one atomic step, or to clarify: do this synchronised:

    1. check read_length, this can be sth like read_length=min(read_length,length);
    2. decrease length with read_length: length-=read_length
    3. get a local copy from offset unsigned int local_offset = offset
    4. increase offset with read_length: offset+=read_length

    Afterwards you can just do a memcpy (or whatever) starting from your local_offset, check if your read goes over circular buffer size (split in 2 memcpy's), ... . This is 'quite' threadsafe, your write method could still write over the memory you're reading, so make sure your buffer is really large enough to minimize that possibility.

    Now, while I can imagine you can combine 3 and 4 (I guess that's what they do in the linked-list case) or even 1 and 2 in atomic operations, I cannot see you do this whole deal in one atomic operation :).

    You can however try to drop 'length' checking if your consumers are very smart and will always know what to read. You'd also need a new woffset variable then, because the old method of (offset+length)%size to determine write offset wouldn't work anymore. Note this is close to the case of a linked list, where you actually always read one element (= fixed, known size) from the list. Also here, if you make it a circular linked list, you can read to much or write to a position you're reading at that moment!

    Finally: my advise, just go with locks, I use a CircularBuffer class, completely safe for reading & writing) for a realtime 720p60 video streamer and I have got no speed issues at all from locking.

提交回复
热议问题