Доступ MS не исправляет пространство для записей, пока Вы не уплотнили базу данных.
Это - что-то, что необходимо регулярно делать к базе данных доступа как часть Вашего обслуживание иначе, Вы закончите с некоторыми довольно болезненными проблемами.
можно уплотнить базу данных любой через Доступ MS, UI (Инструменты-> Утилиты Базы данных->
Компактный и База данных Восстановления) Вас может использовать использование командной строки:
msaccess.exe "target database.accdb" /compact
N.B. Компактный переключатель / должен быть после целевой базы данных
Microsoft Research CHESS should prove to be a good tool for testing your implementation.
Учитывая, что я не могу найти никаких ссылок на то, что Interlocked.Exchange выполняет блоки чтения или записи, я бы сказал, что нет. Я также хотел бы спросить, почему вы хотите отказаться от блокировки, поскольку редко дает достаточно преимуществ, чтобы противостоять его сложности.
Microsoft представила отличную презентацию на GDC в 2009 году, и вы можете получить слайды здесь .
Я подозреваю, что это небезопасно для потоков - представьте себе следующий сценарий:
два потока входят в курсор. Запишите
. Первый доходит до строки node = new Node (x, node);
в истинной половине оператора if (current == BUFFER_SIZE)
(но давайте также предположим, что current == BUFFER_SIZE
), поэтому, когда 1 добавляется к current
, тогда другой входящий поток будет следовать по другому пути через оператор if. Теперь представьте, что поток 1 теряет свой временной интервал, а поток 2 получает его и переходит к вводу оператора if, ошибочно полагая, что условие все еще выполняется. Он должен был ввести другой путь.
Я тоже не запускал этот код, поэтому я не уверен, возможны ли мои предположения в этом коде, но есть ли они (т.е. ввод курсора.
First, I wonder about the assumption in these two lines of sequential code:
node.data[current++] = x;
// We have to use interlocked, to assure that we incremeent the count
// atomicalluy, because the reader could be reading it.
Interlocked.Increment(ref node.count);
What is to say that the new value of node.data[] has been committed to this memory location? It is not stored in a volatile memory address and therefore can be cached if I understand it correctly? Doesn't this potentially lead to a 'dirty' read? There may be other places the same is true, but this one stood out at a glance.
Second, multi-threaded code that contains the following:
Thread.Sleep(int);
... is never a good sign. If it's required then the code is destined to fail, if it isn't required it's a waste. I really wish they would remove this API entirely. Realize that is a request to wait at least that amount of time. With the overhead of context switching your almost certainly going to wait longer, a lot longer.
Third, I completely don't understand the use of the Interlock API here. Maybe I'm tired and just missing the point; but I can't find the potential thread conflict on both threads reading & writing to the same variable? It would seem that the only use I could find for interlock exchange would be to modify the contents of node.data[] to fix #1 above.
Lastly it would seem that the implementation is somewhat over-complicated. Am I missing the point of the whole Cursor/Node thing or is it basically doing the same thing as this class? (Note: I haven't tried it and I don't think this is thread safe either, just trying to boil down what I think your doing.)
class ReaderWriterQueue<T>
{
readonly AutoResetEvent _readComplete;
readonly T[] _buffer;
readonly int _maxBuffer;
int _readerPos, _writerPos;
public ReaderWriterQueue(int maxBuffer)
{
_readComplete = new AutoResetEvent(true);
_maxBuffer = maxBuffer;
_buffer = new T[_maxBuffer];
_readerPos = _writerPos = 0;
}
public int Next(int current) { return ++current == _maxBuffer ? 0 : current; }
public bool Read(ref T item)
{
if (_readerPos != _writerPos)
{
item = _buffer[_readerPos];
_readerPos = Next(_readerPos);
return true;
}
else
return false;
}
public void Write(T item)
{
int next = Next(_writerPos);
while (next == _readerPos)
_readComplete.WaitOne();
_buffer[next] = item;
_writerPos = next;
}
}
So am I totally off-base here and am failing to see the magic in the original class?
I must admit one thing, I despise Threading. I've seen the best developers fail at it. This article gives a great example on how hard it is to get threading right: http://www.yoda.arachsys.com/csharp/singleton.html
Наличие Sleep ()
делает подход без блокировки совершенно бесполезным. Единственная причина столкнуться со сложностями проектирования без блокировок - это потребность в абсолютной скорости и во избежание затрат на семафоры. Использование Sleep (1) полностью противоречит этой цели.
Остерегайтесь двойной проверки - шаблон одиночной блокировки (как в приведенной выше ссылке: http://www.yoda.arachsys.com/csharp/singleton.html )
Дословная цитата из «Современного дизайна C ++» Андрея Александреску