Introducing AtomicQueueMBS – A Thread-Safe Queue for Xojo

With the release of version 25.2 of the MBS Xojo Plugins, we’re excited to introduce the new AtomicQueueMBS class—a powerful tool for managing thread-safe job queues in your Xojo applications.

Whether you’re building a multithreaded server, a background processing system, or any app where tasks need to be scheduled and executed safely across threads, AtomicQueueMBS gives you a robust, atomic queue implementation that works across macOS, Windows, Linux, and iOS.

What is an atomic queue?

AtomicQueueMBS is a generic queue class designed for atomic operations, ensuring thread safety when adding or removing items. It acts as a flexible container for your jobs or data, supporting both FIFO (First-In-First-Out) and LIFO (Last-In-First-Out) behavior.

Example:

Var queue As New AtomicQueueMBS // Add jobs to the queue queue.Push(New MyJob) queue.Push(New MyJob) // Process jobs in another thread Do Var job As MyJob = queue.PopLast // or queue.PopFirst job.Process Loop Until queue.Count = 0

Core Features

  • Fully thread-safe
  • Compatible with all platforms supported by Xojo
  • Works with any type stored as a Variant
  • Simple and intuitive API

Key Properties

  • Count (Read-only) Returns the number of items in the queue.
  • TopValue (Read/Write) Retrieves or sets the value at the top of the queue without removing it.

Powerful Methods

  • Push(value as Variant) Adds a value to the end of the queue.
  • PopFirst / PopLast Removes and returns the first or last item, supporting FIFO or LIFO patterns.
  • Add(values as AtomicQueueMBS) Merges another queue into the current one.
  • Add(values() as Variant) Pushes multiple values at once.
  • Insert(value as Variant) Inserts a value at the front of the queue.
  • Clear() Empties the entire queue.
  • Values() as Variant() Returns all values in the queue as an array.
  • Operator_Convert Allows seamless conversion to a Variant() array:
  Var values() As Variant = queue
  • Operator_Add Enables this elegant syntax:
  queue = queue + 123
  • Operator_Compare Compares two queues for equality.

Use Case: A Multi-Threaded Job Queue

A common use case for AtomicQueueMBSis distributing jobs between multiple threads. For example, one thread can enqueue tasks while several worker threads pop them off concurrently, all without needing to manually handle synchronization.

// Declare the job class
Class MyJob
  Public JobID As Integer

  Sub Constructor(id As Integer)
    JobID = id
  End Sub

  Public Sub Process()
    // Simulate processing time with a simple delay
    System.Sleep(1000)
    System.DebugLog("Processing Job ID: " + JobID.ToString)
  End Sub
End Class

// Declare the main procedure
Sub Main()
  Var queue As New AtomicQueueMBS

  // Main thread pushing jobs into the queue
  For i As Integer = 1 To 5
    queue.Push New MyJob(i)
    System.DebugLog("Pushed Job ID: " + i.ToString)
  Next
  
  // store the queue globally
  app.queue = queue

  // Now, simulate worker threads processing jobs
  For i As Integer = 1 To 3
    // Create and start a worker thread to process jobs
    Var worker As New Thread
    worker.RunAddress = AddressOf WorkerThread
    worker.Identifier = i // Assign worker ID
    worker.Start
  Next
End Sub

// Worker thread procedure
Sub WorkerThread(t As Thread)
  Var queue As AtomicQueueMBS = app.queue ' Receive the queue

  // Simulate worker processing jobs from the queue
  Do
    If queue.Count > 0 Then
      Var job As MyJob = queue.PopFirst // Pop first job in FIFO order
      if job = nil then
         // someone else was quicker
      Else
         job.Process()
      End If
    Else
      System.DebugLog("No jobs to process. Worker " + t.Identifier.ToString + " is idle.")
      Exit Do
    End If
  Loop
End Sub

How This Works:

  1. Main Thread: The main thread creates an AtomicQueueMBS object and pushes five MyJob objects onto the queue. These jobs could represent anything you want to process, like tasks, files, or data.
  2. Worker Threads: Three worker threads are created. Each worker will pull jobs off the queue and process them one by one. The PopFirst method ensures that the jobs are processed in FIFO order (First-In-First-Out).
  3. Processing: The MyJob class simulates a job with an ID and a Process method that uses System.Sleep to mimic a time-consuming task. Once a job is processed, the worker outputs the job ID in the debug log.
  4. Atomic Operations: The AtomicQueueMBSensures thread safety, meaning multiple threads can safely access and modify the queue without conflicts.

Notes:

  • Each worker thread pulls from the same queue, so the tasks are shared across threads.
  • The queue operates atomically, meaning it handles the synchronization internally, so you don’t have to worry about race conditions.

You can modify the WorkerThread to do more complex work depending on your needs, but this demo should provide a basic framework to get started with job queues in a multithreaded environment.

Would you like me to explain any part of the code or further enhance the demo?

Conclusion

The AtomicQueueMBS class simplifies concurrent programming in Xojo by providing a reliable, atomic queue structure. It’s a great addition for developers looking to build high-performance, thread-safe applications across platforms.

This feature is now available in MBS Xojo Plugin 25.2. Try it out today and make your threading logic cleaner, faster, and safer.

Download the latest plugin

Have questions or need examples? Let us know in the comments or reach out directly!

6 Likes

Hallo, wo ist das Beispiel unter Examples abgelegt?

Leider gibt’s keins.

Der Beispielcode ist bei einigen der Methoden in Dokumentation direkt dabei:

I have difficulty understanding this part of the code.
The Xojo Thread class has no RunAddress nor Identifier properties.

The code makes sense, but it doesn’t run.

I hope I’m wrong, but that smells like an AI hallucination to me.

Edit: The “would you like me to expand or enhance the demo” line also seems like it came from an AI response.

4 Likes

Yes, I let AI rewrite it to improve the English.

You need to subclass Thread so you can add Identifier property. Or you use DebugIdentifier property.

And then use AddHandler to connect the Run event:

AddHandler worker.Run, AddressOf WorkerThread

Well, your code clearly states “Var worker As New Thread”, not a subclass.

Yes, it’s DebugIdentifier, not Identifier. Sorry.

Definitely not Christian :grinning_face_with_smiling_eyes:

6 Likes