I am writing a program where one part of the program gets some data while the other part gives in new data at intervals for the first part to work on. This two tasks are to be done independent of each other and concurrently. The time one part stops does not affect the other part in any way. You can call it multitasking, VBasic allows you to do different things at the same time with controls like timers, etc. Any form of help will be greatly appreciated.

Recommended Answers

All 2 Replies

I would say you have 2 options (remembering that the majority of processes, even multi-threaded ones do not actually run concurrently, mostly they time-slice, that is each thread gets a chance to run in turn and while a thread is running non- of the other threads of the process are running).

Firstly you could create a properly multi-threaded program using the API of your OS to create 1 (or more) threads to perform the required tasks. You will need to ensure you protect any data you use in both threads from simultaneous access by both threads, normally done with a mutex (or Critical Section on Windows).

Secondly, if this is a small and simple program you could use a super-loop. Super-loops were more common before the days of (pseudo) multi-tasking (on DOS then) but I still see them occasionally on very low powered micro-processors that really do not need or don't have the resources for an OS.

A super-loop construction is simple, it is a loop (for/while/do while) and each task has a function that is called from the loop. It is important that those task functions do not "pause" because that would interrupt the other tasks. An advantage is that because there is only 1 thread of execution you are guaranteed that when 1 task is running the other tasks are not accessing any data.

The top-level of a super-loop would look something like this

bool task1();
bool task2();

int main()
{
  bool task1Finished;
  bool task2Finished;

  do
  {
    task1Finished = task1();
    task2Finished = task2();
  }
  while(!task1Finished || !task2Finished);

  return 0;
}

But not I would imagine that most people today would consider a super-loop an extremely out-dated design template. (In fact so out-dated I can even find a reference on the interwebs)

commented: good suggestions :) +35

This scenario you are describing is classic in concurrent programming. Most of the time it is referred to as the consumer-producer scheme or just called a buffer between two processes. For multi-threading, I highly recommend using the Boost.Thread library. It is very nice and easy and it will form the basis of the C++ standard threading library (coming up in a few months with the new standard C++0x).

Below is a simple example of a consumer-producer scheme implemented with Boost.Thread. The producer thread fills the buffer with integer values and the consumer grabs those values and outputs the square. This is a classic implementation: it uses a simple queue (FIFO) for the buffer and uses a mutex to prevent the two threads from accessing the queue at the same time. This is not by any means the best implementation (or even a good one), it is just a simple example to show the mechanics of it.

#include <boost/thread/thread.hpp> //this will require linking with "-lboost_thread"

#include <iostream>

#include <queue>

struct int_buffer {
  std::queue<int> data; //holds a simple queue of integer values.
  boost::mutex data_mutex; //holds a mutex that can be used to gain exclusive rights to the buffer.
};

//class for the producer.
class producer {
  private:
    int_buffer& buf; //internal reference to the buffer.
  public:
    producer(int_buffer& aBuf) : buf(aBuf) { };

    //this function is the one that boost::thread object will call to execute the thread.
    void operator()() {
      for(int i=1;i<=1000;++i) {
        boost::unique_lock<boost::mutex> lock_here(buf.data_mutex); //obtain exclusive lock.
        buf.data.push(i); //add a value to the queue.
      };
    };
};

//class for the consumer
class consumer {
  private:
    int_buffer& buf; //internal reference to the buffer.
  public:
    consumer(int_buffer& aBuf) : buf(aBuf) { };

    //this function is the one that boost::thread object will call to execute the thread.
    void operator()() {
      int current_value = 0;
      while(current_value < 1000) { //stop when you have processed the value 1000.
        boost::unique_lock<boost::mutex> lock_here(buf.data_mutex); //obtain exclusive lock.
        if(buf.data.size() > 0) { //check if there is data to process
          current_value = buf.data.front(); buf.data.pop(); //fetches the next value.
          //outputs the square of the value.
          std::cout << "The square of " << current_value << " is " << current_value*current_value << std::endl;
        };
      };
    };
};

int main() {
  int_buffer buf_inter_process; //create a buffer for inter-process communication.

  producer p(buf_inter_process); //links a producer to the buffer.
  consumer c(buf_inter_process); //links a consumer to the buffer.

  boost::thread tp(p); //starts a producer thread.
  boost::thread tc(c); //starts a consumer thread.

  tc.join(); //waits for the consumer thread to be done.
  std::cout << "All threads have finished!" << std::endl;
  
  return 0;
};

You can also use other libraries for threading (like the native ones like Win32 for Windows and pthread for Linux or anything else) but the mechanics are the same in essence.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.