Why Java?Why not C++?

A. First Edition
This is first edition of my one-to-one translation of programming assignment of comp346 from Java
to C++.
B.The problem
In Comp346 we are forced to learn the idiotic programming language of Java and I am personally
 
against this stupid decision of CS department of Concordia though it might be a benefit for students
 
to find a job. However, in my view it will poison student's brain by those idiotic ideas.
 
The following is the stupid code of multi-threading java code.
 
public class Future {
  static int length = 9;                            // 1-indexed semaphores
  static int number = 8;                            // 0-indexed workers 
  static int sum    = 0;

  static Daemon daemon = new Daemon ();
  static Semaphore future[] = new Semaphore[length];
  static int arr[] = new int[] {0, -1, -1, -1, -1, -1, -1, -1, +1};

  public static void main (String[] a) {

    Worker w[] = new Worker[number];

    for( int j=0; j<length; j++ )    // definition before use
      future[j] = new Semaphore (0);

    for( int j=0; j<number; j++ ) {
      w[number-j-1] = new Worker (number-j);
      w[number-j-1].start ();
    }

    System.out.println ("Eight workers have started.");
    System.out.println ("Main thread continues work.");
    for( int j=0; j<number; j++ ) {
      System.out.println ("Main thread waits on semaphore " + (j+1) + ".");
      future[j+1].Wait ();
      System.out.println ("Main thread reads " + arr[j+1] + " from position "
                         + (j+1) + ".");
      sum = sum + arr[j+1];
    }
    System.out.println ("Sum = " + sum);
    for( int j=0; j<number; j++ ) {                 // wait for workers
      try { w[j].join (); }                         // to terminate
      catch (InterruptedException e) { };
    }
    System.out.println ("System terminates normally.");
  }
}

class Daemon {
  private static int d[] = new int[] {0, 4, 4, 4, 6, 4, 6, 4, 6};

  public synchronized void interrupt (int tid) {
    if ( d[tid] > 4 )
    {
      System.out.println("worker "+tid+ " is interrupted.");	
      Thread.yield ();
    }
  }
}

class Semaphore {
  private int value;
  Semaphore (int value1) {
    value = value1;
  }

  public synchronized void Wait () {
    while( value <= 0 ) {
      try { wait (); }
      catch (InterruptedException e) { };
    }
    value--;
  }

  public synchronized void Signal () {
    ++value;
    notify ();
  }
}

class Worker extends Thread {
  private int tid;
  Worker (int tid1) {
    tid = tid1;
  }

  public void run () {
    System.out.println ("Worker " + tid + " begins execution.");
    yield ();
    System.out.println ("Worker " + tid + " doubles own array component.");
    Future.arr[tid] = 2 * Future.arr[tid];
    Future.daemon.interrupt (tid);
    System.out.println ("Worker " + tid + " sets neighbor's array component.");
    Future.arr[tid-1] = 1;
    System.out.println ("Worker " + tid + " signals semaphore " + tid + ".");
    Future.future[tid].Signal ();
    System.out.println ("Worker " + tid + " terminates.");
  }
}

 

 
C.The idea of program
 
There is almost all equivalent functions to use in C++ except that you have to use different function
 
to be equivalent to Java's "notify", depending what synchronized objects you are using, like mutex,
 
semaphore etc.
 
1. However, there is indeed a little difficulty about "cout". You have to sychronized it
 
by yourself otherwise different threads might mess up all messages. So, I designed a mutex for all
 
thread, including main thread, to wait for it before output and release it after displaying.
 
This method has a potential effect that it divides the programming execution by all "displaying"
 
methods. It means that your thread will not be able to be "atomic" across "display" unless you use
 
a higher level "critical region" method to bind them into an atomic part.
 
2. By changing array of "daemon" you will get random result ranging from 9 to 16.
 
3. The professor's mistake on Java is to make the "interrupt" method of Daemon class to be
 
"synchronized" which makes the function "interrupt" an atomic. The immediate effect is that all
 
threads are blocked before "interrupt" after first interruption happens. And because the "yield" is
 
within the "interrupt" function, it won't return until the thread get next chance to run CPU. So,
 
all threads are queuing up before "interrupt", and the "interrupt" doesn't function like a
 
"interrupt" at all. This is explained perfectly clear by Mr. Mokhov. What a wonderful explanation!
D.The major functions
E.Further improvement
F.File listing
1. semaphore.cpp (main)

file name: semaphore.cpp (main)
#include <iostream>
#include <windows.h>

using namespace std;

const int ThreadCount=8;

int array[ThreadCount+1]={1,-1,-1,-1,-1,-1,-1,-1,-1};

HANDLE mutex;

int params[ThreadCount]={0,1,2,3,4,5,6,7};

int daemon[ThreadCount]={1,1,5,1,6,1,6,1};

DWORD WINAPI run(LPVOID param);

HANDLE Workers[ThreadCount];

HANDLE semaphores[ThreadCount];

void interrupt(int i);

void display(char* str, int i);

int main()
{	
	int sum=0;
	//this is mutex for cout, otherwise output will be messed up.
	mutex=CreateMutex(NULL, false, NULL);
	//create semaphores and initialized to unsignaled
	for (int i=0; i<ThreadCount; i++)
	{
		semaphores[i]=CreateSemaphore(NULL, 0, 1, NULL);
	}
	//create threads with suspended and in descending order of index
	for (i=ThreadCount-1; i>=0; i--)
	{
		Workers[i]=CreateThread(NULL, 0, run, &params[i], CREATE_SUSPENDED , NULL);		
	}
	display("Eight worker have started", -1);
	display("Main thread continues to work", -1);
	
	//equivalent to "start"
	for (i=0; i<ThreadCount; i++)
	{
		ResumeThread(Workers[i]);
	}

	for (i=0; i<ThreadCount; i++)
	{		
		display("main thread waits on semaphore ", i);			
		
		WaitForSingleObject(semaphores[i], INFINITE);
		
		display("main thread reads  ", array[i]);
		
		sum+=array[i];
	}
	display("the sum is ", sum);

	return 0;
}

void display(char* str, int i)
{
	WaitForSingleObject(mutex, INFINITE);

	cout<<str;
	if (i!=-1)
	{
		cout<<i;
	}
	cout<<"\n";
	ReleaseMutex(mutex);
}


void interrupt(int i)
{
	if (daemon[i]>4)
	{
		display("interrupt of worker ", i);
		Sleep(0);
	}
}

//if you want to get result of 16, you have to comment out all
//display() because in order to "cout" properly, I used a "mutex"
//to block all concurrent "cout" within "display".
//So, you see all "displays" "divides" executions into independent 
//parts, therefore the output is always 9 unless displays are commented out.
DWORD WINAPI run(LPVOID parameter)
{
	//at first I thought I cannot declare local variable to replace this 
	//but finally I understand that thread has its own stack and some 
	//local variable, right?
	int i=*((int*)(parameter));
	
	display(" begins execution of worker of ", i);
	//display(" begins execution of worker of ", i);
	Sleep(0);
	//display(" doubles own array component of worker of ", i);
	
	array[i]*=2;
	//array[*((int*)(parameter))]*=2;//
	

	//the Professor's mistake is to add "synchronized" in front of 
	//interrupt, so it is equivalent to add a "wait" here
	//and a release "mutex" or "semaphore after "interruption"
	//This is explained very clearly by Mr. Mokhov and I learned it from 
	//him. Well done!

	interrupt(i);
	//interrupt(*((int*)(parameter)));	
	//display(" set neighbour's array component of worker ", i);

	array[i+1]=1;
	//array[*((int*)(parameter))+1]=1;

	//display("send semaphore to ", i);

	ReleaseSemaphore(semaphores[i], 1, NULL);	
	//display("terminates of worker of ", i);

	return i;
}







Here is the result: 
Eight worker have started
Main thread continues to work
begins execution of worker of 0
begins execution of worker of 1
begins execution of worker of 2
begins execution of worker of 3
begins execution of worker of 4
begins execution of worker of 5
begins execution of worker of 6
begins execution of worker of 7
main thread waits on semaphore 0
interrupt of worker 2
interrupt of worker 4
interrupt of worker 6
main thread reads 2
main thread waits on semaphore 1
main thread reads 2
main thread waits on semaphore 2
main thread reads 2
main thread waits on semaphore 3
main thread reads 1
main thread waits on semaphore 4
main thread reads 2
main thread waits on semaphore 5
main thread reads 1
main thread waits on semaphore 6
main thread reads 2
main thread waits on semaphore 7
main thread reads 1
the sum is 13
Press any key to continue


                                 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)