0

I created a situation where a producer class adds strings to a queue in a controller class. The controller class notifies the worker class that there is work and executes the work, in this case appending strings to a file. I'm not able to get this work. The file is created but nothing is appending. I created this situation in java where I succeeded. I will put this code at the end. Just to clearify I need solve this in C#.

With using the debugger I came to the conclusion that the thread doesn't wake up after going into wait. I could be wrong however.

As a note: I do not want to use coroutines

Producer method:

void Start () {
    for (int i = 0; i < 100; i++)
    {
        Ccontroller.Instance.AddWork("no: " + i);
    }   
}

Controller class For locking I tried Monitor.enter/exit and current solution. I changed the implementation abit for easyness. This implementation uses the worker static queue. The static queue was needed for the thread.

public class Ccontroller : Singleton<Ccontroller>
{
public Queue<string> workLoad = new Queue<string>();
public Worker worker;

public Object lockGetWork = new Object();

public void AddWork(string toProcess)
{
    Worker.workload.Enqueue(toProcess);

    lock (lockGetWork)
    {
        Monitor.PulseAll(lockGetWork);
    }
}

public string GetWork()
{
    string process;

    process = workLoad.Dequeue();

    return process;
}
}

Worker class: public class Worker : MonoBehaviour {

static string path = @"d:\test.txt";
Thread t;

public static Queue<string> workload = new Queue<string>();

private void Awake()
{
    t = new Thread(Work);
}

// Use this for initialization
void Start()
{
    //create file
    if (!File.Exists(path))
    {
        using (StreamWriter sw = File.CreateText(path)) { }
    }
    t.Start();
}

static void Work()
{

while (true)
{
    if (workload.Peek() != null)
        {
            using (StreamWriter sw = File.AppendText(path))
            {
                sw.WriteLine(workload.Dequeue());
            }
        }
        else
        {
            Monitor.Wait(Ccontroller.Instance.lockGetWork);
        }
    }
}
}

Code in Java code and desired situation: Method in producer class:

public void StartWork(){
    for(int i=0; i<200; i++){

        controller.AddWork("work order: "+i);
    }
}

The controller:

public class WorkController {

private Queue<String> workload = new ArrayDeque<String>();
private AtomicInteger LockAdd = new AtomicInteger();
private AtomicInteger LockRemove = new AtomicInteger();

public void AddWork(String work){
        workload.add(work);
        synchronized(LockAdd){
            LockAdd.notify();
        }       
}

public String RemoveWork(){
    String work;
    synchronized(LockRemove){
        work= workload.remove();
    }
    return work;
}  
}

The worker:

public class Worker {

public WorkController controller;

Thread work = new Thread(){
    public void run(){
        while(true){
            try{
                System.out.println(controller.RemoveWork());
            }catch(NoSuchElementException ex){
                 System.out.println("no work");
                try {
                    wait();
                } catch (InterruptedException ex1) {
                    Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex1);
                }
            }
        }
    }
};

void StartWorker(){
    work.start();
}

}
Sjoerd Brauer
  • 129
  • 1
  • 12
  • 1
    Unity is not thread-safe... But if you're doing something that doesn't touch unity code you might as well just make it a seperate proces – johnny 5 Mar 24 '17 at 14:32

1 Answers1

0

What solved the problem: It seems that in Unity and/or c# you to do Monitor.wait within a Lock statement of the same object.

Sjoerd Brauer
  • 129
  • 1
  • 12