Взаимодействующие потоки выполняют поставленную перед ними задачу. При этом один поток обеспечивает генерацию данных, а второй – обработку получаемых данных. Если при этом время, необходимое для генерации данных и время обработки данных различаются, проблема взаимодействия потоков может быть решена посредством очереди данных, которая в этом случае играет роль буфера между двумя потоками. Первый поток размещает данные в очередь “с одного конца”, абсолютно не интересуясь успехами потока-обработчика. Второй поток извлекает данные из очереди “с другого конца” руководствуясь исключительно состоянием этой очереди. Отсутствие данных в очереди для потока-обработчика означает успешное выполнение поставленной задачи или сигнал к самоусыплению.
Организация работы потоков по этой схеме предполагает:
§ выделение обрабатываемых данных в отдельный класс,
§ создание общедоступного объекта-представителя класса “Очередь” с интерфейсом, обеспечивающим размещение и извлечение данных,
§ разработку классов, содержащих методы генерации и обработки данных, реализующих интерфейс доступа к данным,
§ разработку методов обратного вызова, сообщающих о результатах выполнения задач генерации и обработки данных,
§ создание и запуск потока, обеспечивающего генерацию данных и размещение данных в очереди,
§ создание и запуск потока, обеспечивающего извлечение данных из очереди и обработку данных.
Пример
using System;
using System.Threading;
using System.Collections;
namespace CommunicatingThreadsQueue
{
public delegate void CallBackFromStartClass (string param);
// Данные. Предмет и основа взаимодействия двух потоков.
class CommonData
{
private int iVal;
public int iValProp
{
get
{
return iVal;
}
set
{
iVal = value;
}
}
public CommonData(int key)
{
iVal = key;
}
}
// Классы Receiver и Sender: основа взаимодействующих потоков.
class Receiver
{
Queue cdQueue;
CallBackFromStartClass callBack;
// Конструктор умолчания...
public Receiver(ref Queue queueKey, CallBackFromStartClass cbKey)
{
cdQueue = queueKey;
callBack = cbKey;
}
public void startReceiver()
{
DoIt();
}
// Тело рабочей функции...
public void DoIt()
{//====================================
CommonData cd = null;
while (true)
{
Console.WriteLine(“Receiver. notifications in queue: {0}”,cdQueue.Count);
if (cdQueue.Count > 0)
{
cd = (CommonData)cdQueue.Dequeue();
if (cd == null)
Console.WriteLine(“?????”);
else
{
Console.WriteLine(“Process started ({0}).”, cd.iValProp);
// Выбрать какой-нибудь из способов обработки полученного уведомления.
// Заснуть на соответствующее количество тиков.
//Thread.Sleep(cd.iValProp);
// Заняться элементарной арифметикой. С усыплением потока.
while (cd.iValProp != 0)
{
cd.iValProp--;
Thread.Sleep(cd.iValProp);
Console.WriteLine(“process:{0}”,cd.iValProp);
}
}
}
else
callBack(“Receiver”);
Thread.Sleep(100);
}
}//====================================
}
class Sender
{
Random rnd;
int stopVal;
Queue cdQueue;
CallBackFromStartClass callBack;
// Конструктор...
public Sender(ref Queue queueKey, int key, CallBackFromStartClass cbKey)
{
rnd = new Random(key);
stopVal = key;
cdQueue = queueKey;
callBack = cbKey;
}
public void startSender()
{
sendIt();
}
// Тело рабочей функции...
public void sendIt()
{//====================================
while (true)
{
if (stopVal > 0)
{
// Размещение в очереди нового члена со случайными характеристиками.