Вы можете использовать классы монитора C #, которые поддерживаются ключевым словом "lock".
По сути, ваш метод может быть заключен в блокировку (lockobj) {CallMethod ()}
Это обеспечит вам защиту, если предположить, что все потоки находятся в одном процессе.
Вам понадобится Mutex, если вам нужно заблокировать все процессы.
Что касается вашей программы, я бы посмотрел на то, как поместить статическую метку времени и кэшированное значение в ваш метод. Поэтому, когда метод входит, если отметка времени находится в допустимом диапазоне, возвращает кэшированное значение, в противном случае просто выполните выборку. В сочетании с механизмом блокировки это должно делать то, что вам нужно.
Конечно, это предполагает, что время, которое нужно взять и заблокировать на мониторе C #, не повлияет на производительность вашего приложения.
UPDATE:
Я обновил ваш код, чтобы показать вам, что я имел в виду, используя кеш и метку времени. Я предположил, что ваша переменная «motorsData» - это то, что возвращается из опроса двигателя, и поэтому у меня нет переменной для нее. Однако, если я неправильно понял, просто добавьте переменную, в которой хранятся данные после того, как они возвращаются из кода. Примечание. Я не проверял ошибки для вас, поэтому вам нужно разобраться с вашими исключениями.
static DateTime lastMotorPoll;
const TimeSpan CACHE_PERIOD = new TimeSpan(0, 0, 0, 0, 250);
private object cachedCheckMotorsDataLock = new object();
private void CachedCheckMotorsData()
{
lock (cachedCheckMotorsDataLock) //Could refactor this to perform a try enter which returns quickly if required
{
//If the last time the data was polled is older than the cache period, poll
if (lastMotorPoll.Add(CACHE_PERIOD) < DateTime.Now)
{
pollMotorsData();
lastMotorPoll = DateTime.Now;
}
else //Data is fresh so don't poll
{
return;
}
}
}
private void pollMotorsData()
{
// Execute single poll with "foreground" handshaking
DateTime start = DateTime.Now;
byte retryCount = 0;
// Pick old data atomically to detect change
uint motorsDataTimeStampPrev = this.MotorsDataTimeStamp;
bool changeDetected = false;
try
{
do
{
// Handshake signal to DPRAM write process on controller side that host PC is reading
this.controller.deltaTauTcpClient.Pmac_SetBit(OFFSET_0x006A_BIT15_FOREGROUND_READ, 15, true);
try
{
bool canReadMotors = false;
byte[] canReadFrozenDataFlag = new byte[2];
do
{
this.controller.deltaTauTcpClient.Pmac_GetMem(OFFSET_0x006E_BIT15_FOREGROUND_DONE, canReadFrozenDataFlag);
canReadMotors = (canReadFrozenDataFlag[1] & 0x80) == 0x80;
if (canReadMotors) break;
retryCount++;
Thread.Sleep(1);
} while (retryCount < 10);
if (!canReadMotors)
{
throw new DeltaTauControllerException(this.controller, "Timeout waiting on DPRAM Foreground Handshaking Bit");
}
// Obtain fresh content of DPRAM
this.controller.deltaTauTcpClient.Pmac_GetMem(OFFSET_0x006A_394BYTES_8MOTORS_DATA, this.motorsData);
this.motorsDataBorn = DateTime.Now;
}
finally
{
// Handshake signal to DPRAM write process on controller side that host PC has finished reading
this.controller.deltaTauTcpClient.Pmac_SetBit(OFFSET_0x006A_BIT15_FOREGROUND_READ, 15, false);
}
// Check live change in a separate atom
changeDetected = this.MotorsDataTimeStamp != motorsDataTimeStampPrev;
} while ((!changeDetected) && ((DateTime.Now - start).TotalMilliseconds < 255));
// Assert that result is live
if (!changeDetected)
{
throw new DeltaTauControllerException(this.controller, "DPRAM Background Data timestamp is not updated. DPRAM forground handshaking failed.");
}
}
}