我有一个有两个线程的应用程序。
第一个(主线程)使用套接字捕获数据并更新DataTables
第二个将DataTables插入数据库。
应用程序工作正常,但当它关闭时,主线程完成读取数据并在第二个线程中调用Abort方法,这可能会插入到数据库中,这会导致数据不一致。
目前我使用以下解决方案来克服“插入时中止”
编辑: 在强大的答案后,我改变了代码
void MainThread()
{
while(Read())
{
//Read Data through socket
try
{
//Wait on Mutex1
//Update Tables
}
finally
{
//Release Mutex1
}
}
_isrunning = false;
_secondThread.Join();
}
void SecondThread()
{
while(_isrunning)
{
try
{
//Wait on Mutex1
//Insert Tables into Database using transactions
}
finally
{
//Release Mutex1
}
}
}
答案 0 :(得分:8)
只要两个线程都没有标记为后台线程,应用程序将继续运行,直到两个线程都退出。所以,你需要做的就是让每个线程分别完全退出。对于写入数据库的线程,这可能意味着耗尽生产者/消费者队列并检查要退出的标志。
我展示了一个合适的生产者/消费者队列here - 工人就是:
void WriterLoop() {
SomeWorkItem item; // could be a `DataTable` or similar
while(queue.TryDequeue(out item)) {
// process item
}
// queue is empty and has been closed; all done, so exit...
}
以下是基于SizeQueue<>
的完整示例 - 请注意,在读者和编写者干净地退出之前,该过程不会退出。如果您不想排空队列(即您想要更快退出,并忘记任何待处理的工作),那么很好 - 在某处添加额外的(易失性)标记。
static class Program {
static void Write(object message) {
Console.WriteLine(Thread.CurrentThread.Name + ": " + message);
}
static void Main() {
Thread.CurrentThread.Name = "Reader";
Thread writer = new Thread(WriterLoop);
writer.Name = "Writer";
var queue = new SizeQueue<int>(100);
writer.Start(queue);
// reader loop - note this can run parallel
// to the writer
for (int i = 0; i < 100; i++) {
if (i % 10 == 9) Write(i);
queue.Enqueue(i);
Thread.Sleep(5); // pretend it takes time
}
queue.Close();
Write("exiting");
}
static void WriterLoop(object state) {
var queue = (SizeQueue<int>)state;
int i;
while (queue.TryDequeue(out i)) {
if(i%10==9) Write(i);
Thread.Sleep(10); // pretend it takes time
}
Write("exiting");
}
}
答案 1 :(得分:6)
假设“call abort方法”意味着使用Thread.Abort中止线程。 Don't do that
您实际上是在崩溃您的应用。使用监视器有很多更简洁的方法。
尽管如此,当您的应用程序崩溃时,您不应该在数据库中获取不一致的数据,这就是您拥有ACID属性的数据库事务的原因。
非常重要的编辑 您说:出于性能原因,您不使用事务,而是使用互斥锁。在很多级别上,这是错误。首先,事务可以使某些操作更快,例如尝试在表中插入10行,在事务中再次尝试,事务版本会更快。其次,如果你的应用程序崩溃,你会破坏你的数据库会发生什么?当您的应用的多个实例正在运行时会发生什么?或者在查询分析器中针对数据库运行报告时?
答案 2 :(得分:3)
您的互斥锁等待应该包含超时。每个线程的外部循环都可以检查“请立即关闭”标志。要关闭,请为每个线程设置“please now now”标志,然后使用“join”等待每个线程完成。