Why threads order yields different results for fork...join_none?

In reply to mlsxdx:

For case 1 and case 2, you cannot rely on the ordering of the processes started by a fork/join block - these are race conditions. It just so happens that your simulator chooses to execute them in the order they appear in the source code. If you need a predictable ordering, then you need to use a begin/end instead of fork/join.

For case 1, the consumer executes first before any producer has done a put() into the mailbox, so checker_data.num() == 0. For case 2, the consumer executes last after all producers have done put()s into the mailbox, so checker_data.num() == 3.

As I said above, the get() is your blocking delay, there is no need for a #1.

 task automatic consumer();
      bit [7:0] data;
      while(1) begin // I would use 'forever begin'
          checker_data.get(data); // blocks until the get() succeeds 
          $display($time,,"Got data:%0h",data);
      end
  endtask

Also, use $urandom instead of $random. You get stable seeding of each process regardless of execution ordering of the threads.