Design and Implementation of Message Queue

Source: Internet
Author: User
Introduction

Message-driven mechanism is the basis of the GUI system. One of the underlying infrastructure of message-driven is message queue, which is the hub of the entire GUI system, this article introduces a Message Queue Implementation Method Based on the ring queue, and provides its data structure, main operation flow and core code.

Ring queue

A loop queue is a data structure of a queue connected at the beginning and end. It follows the FIFO principle, as shown in:

Ring Buffer

In a circular queue, a set of sequential address storage units are used to store elements from the queue header to the end of the queue. The read and write positions are directed by the read_pos and write_pos pointers respectively.

When the queue is initialized, the value of read_pos = write_pos = 0. When a new element is written, the value of write_pos increases by 1. When an element is read, the value of read_pos increases by 1. If the queue is full, data cannot be written to the queue. If the queue is empty, data cannot be read. The method for determining whether the column is full is to check (write_pos + 1) % queue_size = read_pos is true, and the method for determining whether the queue is empty is to check whether write_pos = read_pos is true.

In view of the mutual exclusion and synchronization between threads when multiple threads access the ring queue at the same time, it is proposed to use a lock to control multiple threads to access the ring queue at the same time, and use a semaphore to control the synchronization between threads.

Within a period of time, only one thread can obtain the lock. When it holds the lock, other threads must wait to access the ring queue until the lock is released. As a result, the lock ensures that multiple threads access the circular queue mutex.

The thread first checks whether the semaphore is greater than 1 from the queue, and if so, reads data from the queue; otherwise, enters the waiting state until the semaphore is greater than 1; after a thread writes data to the queue, it will increase the semaphore by 1. If a thread is waiting, it will be awakened. As a result, semaphores implement synchronous access to the circular queue with multiple threads.

Flowchart

It is the main process of ring buffer initialization, Data Reading, and Data Writing.

Ring buffer Flowchart
  • Allocate memory space for the Ring queue during initialization and complete the initialization of the lock and semaphore;
  • If you write data to the ring queue, you must first obtain the lock. If the lock is occupied, it enters the waiting state. Otherwise, you can determine whether the ring queue is full. If the queue is full, the lock is released and returned. If the queue is not full, the data is written to the write_pos position, and the write_pos position is increased by 1. The lock is released and the semaphore is increased by 1, indicating that a data has been written;
  • If data is read from the ring queue, first determine whether the semaphore is greater than 1. If not, wait. Otherwise, obtain the lock. If the lock is occupied, wait, otherwise, read data from read_pos, add read_pos to 1, release the lock, and read the data.
Data Structure

The data structure of the ring queue is as follows:

typedef _MSG {    int message;    void* param;} MSG;typedef _MSGQUE {    pthread_mutex_t lock;    sem_t  wait;    MSG* msg;    int size;    int read_ops;    int write_ops;} MSGQUEUE;

The ring queue includes the following data:

  • Lock: mutex lock;
  • Wait: semaphore
  • MSG: pointer to the data zone;
  • Size: Maximum number of data in a ring queue;
  • Read_ops: Read location;
  • Write_ops: Write location.
Queue Initialization

Initialization mainly completes three tasks:

  • Allocate memory for the Ring queue;
  • Initialize the mutex lock and use pthread_mutex_init;
  • Initialize the semaphore and use sem_init.
/* Create message queue */_msg_queue = malloc (sizeof (MSGQUEUE));/* init lock and sem */pthread_mutex_init (&_msg_queue->lock, NULL);sem_init (&_msg_queue->wait, 0, 0);/* allocate message memory */_msg_queue -> msg = malloc (sizeof(MSG) * nr_msg);_msg_queue -> size = nr_msg;
Write operation

As described in the flowchart above, write operations mainly include the following steps:-get the lock;

  • Determines whether the queue is full;
  • If it is not full, write the data to write_pos, add write_pos to 1, and determine whether write_pos is out of bounds;
  • Release the lock and increase the semaphore by 1.
/* lock the message queue */pthread_mutex_lock (_msg_queue->lock);/* check if the queue is full. */if ((_msg_queue->write_pos + 1)% _msg_queue->size == _msg_queue->read_pos) {    /* Message queue is full. */    pthread_mutex_unlock (_msg_queue->lock);    return;}/* write a data to write_pos. */_msg_queue -> msg [write_pos] = *msg;write_pos ++;/* check if write_pos if overflow. */if (_msg_queue->write_pos >= _msg_queue->size)    _msg_queue->write_pos = 0;/* release lock */pthread_mutex_unlock (_msg_queue->lock);sem_post (_msg_queue->wait);
Read operations

Similarly, read operations are divided into the following steps:

  • Check semaphores;
  • Obtain the lock;
  • Determines whether the queue is empty;
  • If it is not empty, read the data at read_ops, add read_ops to 1, and determine whether read_pos is out of bounds;
  • And release the lock.
sem_wait (_msg_queue->wait);/* lock the message queue */pthread_mutex_lock (_msg_queue->lock);/* check if queue is empty */if (_msg_queue->read_pos != _msg_queue->write_pos) {    msg = _msg_queue->msg + _msg_queue->read_pos;/* read a data and check if read_pos is overflow */    _msg_queue->read_pos ++;    if (_msg_queue->read_pos >= _msg_queue->size)        _msg_queue->read_pos = 0;    return;}/* release lock*/pthread_mutex_unlock (_msg_queue->lock);
Problem
  • The circular queue used in this article is of a fixed length and can be further improved to design a circular queue with a variable length;
  • The message queue in this article is based on the "first-in-first-out" principle and does not consider messages with priority. However, this situation exists;
  • This article focuses on the principles and implementation of message queues. For a GUI program, a message loop is also required to work with the message queue. The message loop will be separately summarized.

Http://www.linuxgraphics.cn/gui/message_queue.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.