class ThreadCommunication {

    private const int NUMBER_OF_MESSAGES = 200000;
    private AsyncQueue<DataBox> async_queue;

    public ThreadCommunication () {
        this.async_queue = new AsyncQueue<DataBox> ();
    }

    // data object for sending
    private class DataBox {

        public int number { get; private set; }
        public string name { get; private set; }

        public DataBox (int number, string name) {
            this.number = number;
            this.name = name;
        }
    }

    private void* writing_func () {
        var timer = new Timer ();
        timer.start ();
        for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
            // prepare an object to send
            var databox = new DataBox (i, @"some text for value $i");
            // send a message to the queue
            async_queue.push (databox);
        }
        // show time result
        print ("Pushed %d DataBoxes into AsyncQueue in %f s\n", NUMBER_OF_MESSAGES, timer.elapsed ());
        return null;
    }

    private void* reading_func () {
        var timer = new Timer ();
        timer.start ();
        for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
            // receive a message from the queue
            var databox = async_queue.pop ();

            // make sure the content is right
            assert (i == databox.number);
            assert (@"some text for value $i" == databox.name);

            // show one of the strings
            if ((NUMBER_OF_MESSAGES / 2) == databox.number) {
                print ("\tNO: %d \tTEXT: %s\n", databox.number, databox.name);
            }
        }
        // show time result
        print ("Popped %d DataBoxes from AsyncQueue in %f s\n", NUMBER_OF_MESSAGES, timer.elapsed ());
        return null;
    }

    public void run () {
        try {
            unowned Thread<void*> thread_a = Thread.create<void*> (writing_func, true);
            unowned Thread<void*> thread_b = Thread.create<void*> (reading_func, true);

            // Wait until the threads finish
            thread_a.join ();
            thread_b.join ();

        } catch (ThreadError e) {
            stderr.printf ("%s\n", e.message);
            return;
        }
    }
}

void main () {
    var thread_comm = new ThreadCommunication ();
    thread_comm.run ();
}
