Потокобезопасность и делегаты с генерируемых чисел


В основном классе, петли генерировать номера (0~100), и когда его генерируемое число > 20, то его значение передается в поток, где он имитирует некоторые работы с этим номером. Между тем, в то время как это число обрабатывается, другие генерируемых чисел > 20 должны быть пропущены.

Это код ОК? Я не уверен, если я делаю что-то плохое или нет. На самом деле это, кажется, работает нормально, но я не знаю, если это может быть написано таким образом, или даже "лучше".

class Program
{
    delegate void SetNumberDelegate(int number);
    delegate bool IsBusyDelegate();

    static void Main(string[] args)
    {
        Random rnd = new Random();
        ProcessingClass processClass = new ProcessingClass();
        SetNumberDelegate setNum = new SetNumberDelegate(processClass.setNumber);
        IsBusyDelegate isBusy = new IsBusyDelegate(processClass.isBusy);
        Thread processThread = new Thread(new ThreadStart(processClass.processNumbers));
        processThread.Start();
        int num;
        int count = 0;
        while (count++ < 100)
        {
            num = rnd.Next(0, 100);
            Console.WriteLine("Generated number {0}", num);
            if (num > 20)
            {
                if (!isBusy())
                {
                    setNum(num);
                }
                else
                {
                    Console.WriteLine("Thread BUSY! Skipping number:{0}", num);
                }
            }
            Thread.Sleep(1);
        }
        processThread.Abort();
        processThread.Join();
        Console.ReadKey();
    }
}
class ProcessingClass
{
    private volatile bool busy;
    private volatile int number;

    public ProcessingClass()
    {
        busy = false;
        number = -1;
    }

    public bool isBusy()
    {
        return busy;
    }

    public void setNumber(int num)
    {
        number = num;
    }

    public void processNumbers()
    {
        while (true)
        {
            if (number > -1 && !busy)
            {
                busy = true;
                Console.WriteLine("Processing number:{0}", number);
                // simulate some work with number e.g. computing and storing to db
                Thread.Sleep(500); 
                Console.WriteLine("Done");
                number = -1;
                busy = false;
            }
        }
    }
}


1938
4
задан 17 сентября 2011 в 06:09 Источник Поделиться
Комментарии
4 ответа

Нет синхронизации здесь и так все доступ к государственным нить подвергается гонки данных. Это всесторонне не ориентирована на многопотоковое исполнение.

От того, что я могу сказать все, что вам нужно, это реализовать производитель/узор потребителя. Сделать это с блокирующей очереди. Пожалуйста, не используйте занят петлями. Они горят циклов процессора и ужасно непродуктивных.

3
ответ дан 17 сентября 2011 в 06:09 Источник Поделиться

Почему бы не использовать BackgroundWorker?

static void Main(string[] args)
{
Random rnd = new Random();
int count = 0, num;

BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);

while(count++ < 100)
{
num = rnd.Next(0, 100)
Console.WriteLine("Generated number {0}", num);
if(num > 20)
{
if(!bw.IsBusy)
bw.RunWorkerAsync(); //calls bw_DoWork function
else
Console.WriteLine("Thread BUSY! Skipping number:{0}", num);
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//do something with number in background
}
}

Если вы хотите, чтобы прервать, позвоните БВ.CancelWorkerAsync().

3
ответ дан 8 апреля 2014 в 05:04 Источник Поделиться

Я думаю, что это должно делать то, что вы ожидали.
Добавляет все числа больше 20, если нет номера в очереди потока.

Пожалуйста, оставьте комментарий если вы хотели сделать что-то другое, я бы рада давать вам право примеры.

class Program
{
delegate void SetNumberDelegate (int number);

delegate bool IsBusyDelegate ();

static void Main (string[] args) {
Random rnd = new Random ();
ProcessingClass processClass = new ProcessingClass ();

ManualResetEvent resetEvent = new ManualResetEvent (false);
ThreadPool.QueueUserWorkItem (processClass.ProcessNumbers, resetEvent);

int num;
int count = 0;
while (count++ < 100) {
num = rnd.Next (0, 100);
Console.WriteLine ("Generated number {0}", num);

if (num > 20) {
if (!processClass.IsBusy) {
processClass.Enqueue (num);
} else {
Console.WriteLine ("Thread BUSY! Skipping number:{0}", num);
}
}
System.Threading.Thread.Sleep (1);
}
resetEvent.WaitOne ();
Console.ReadKey ();
}
}

class ProcessingClass
{
readonly Queue numberQueue = Queue.Synchronized (new Queue ());
bool aborting = false;
object abortingLock = new object ();

public bool Aborting {
get {
lock (abortingLock) {
return aborting;
}
}
set {
lock (abortingLock) {
aborting = value;
}
}
}

public bool IsBusy {
get {
return numberQueue.Count > 0;
}
}

public void Abort () {
Aborting = true;
}

public void Enqueue (int num) {
lock (numberQueue) {
numberQueue.Enqueue (num);
Monitor.PulseAll (numberQueue);
}

}

public int Dequeue () {
lock (numberQueue) {
if (numberQueue.Count == 0)
Monitor.Wait (numberQueue);
return (int)numberQueue.Dequeue ();
}

}

public void ProcessNumbers (object threadContext) {
//please create an own class for this!
ManualResetEvent resetEvent = (ManualResetEvent)threadContext;
//
StartProcessingNumbers ();
resetEvent.Set ();

}

private void StartProcessingNumbers () {
while (!aborting) {
int num = Dequeue ();
Console.WriteLine ("Processing number:{0}", num);
// simulate some work with number e.g. computing and storing to db
System.Threading.Thread.Sleep (200);
Console.WriteLine ("Done");
}
}
}

2
ответ дан 30 сентября 2011 в 06:09 Источник Поделиться

Это не потокобезопасными на все... для таких вещей (производитель/потребитель) использовать методом blockingcollection - см. MSDN ссылка, включая пример кода на http://msdn.microsoft.com/en-us/library/dd997371.aspx

1
ответ дан 17 сентября 2011 в 09:09 Источник Поделиться