两个线程之间有同步也有异步执行,请高手帮我看看这样写对不对。

panwen516 2009-07-08 10:45:34
有两个线程A,B;A线程往表里面写数据,B线程交换数据,同时关闭当前表的触发器。注意:A,B操作的表都有触发器。

当A线程往TA表写数据时,TA表触发器往状态表写数据,这条数据是有效的。当B线程交换数据时,往TA或其他表写数时,TA触发器或其他表触发器也会往状态表写数据,但这条数据是无效的。所以,我的方法是,当B线程在交换数据前,先将要交换的表的触发器禁用,等交换完成后在启用触发器。这样会出现一个问题,如果线程A和B同时操作同一张表,当B线程先执行禁用触发器,数据还没有交换完成,触发器还没有被启用时,然后A线程往表里面写入数据,这时因为触发器关闭也就不会往状态表中写入数据了,所以这样操作是错误的;反过来,当A线程往同一张表写数据时,B线程是不应该禁用触发器的,这就是两个线程同步情况。但两个线程操作的不是同一张表,同步情况就不会存在了。所以,为什么说两个线程之间有同步也有异步。

所以,我模拟了以上的情况,写了一个Demo,请大家帮我看看,这样设计会不会出现问题。谢谢。(最好复制下来,调试)


/// <summary>
/// 两线程实现同步数据类
/// </summary>
public class ElementA
{
static string tableA = string.Empty;//A表名
static string tableB = null;//B表名
static bool signal = false;//是否需要同步

static CriticalRegion cr = new CriticalRegion();//临界区
/// <summary>
/// A表名
/// </summary>
public string TableA
{
set
{
tableA = value;
if (tableA == tableB)
signal = true;
else
signal = false;
}
}
/// <summary>
/// B表名
/// </summary>
public string TableB
{
set
{
tableB = value;
if (tableB == tableA)
signal = true;
else
signal = false;
}
}
/// <summary>
/// 是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
/// </summary>
public bool Signal
{
get { return signal; }
}
/// <summary>
/// 临界区
/// </summary>
public CriticalRegion CriticalRegion
{
get { return cr; }
set { cr = value; }
}
//public Object LockObject
//{
// get { return lockobject; }
//}
}
/// <summary>
/// 临界区类
/// </summary>
public class CriticalRegion
{
bool criticalRegionControl = false;
/// <summary>
/// 临界区控制,TRUE表示有线程在执行;FALSE表示没有线程在执行,可以进入
/// </summary>
public bool CriticalRegionControl
{
get { return criticalRegionControl; }
set { criticalRegionControl = value; }
}
}

//////////////////////////////////////////
/// <summary>
/// 线程A会执行里面的方法
/// </summary>
public class RunA
{
public void Run(object da)
{
ElementA data = (ElementA)da;
string[] A = new string[] { "A", "B", "C", "A", "C", "A", "A", "C" };//模拟的数据表名
for (int i = 0; i < A.Length; i++)
{

data.TableA = A[i];//改表名
if (data.Signal)//判断两线程是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
{
if (data.CriticalRegion.CriticalRegionControl == true)//判断临界区是否有线程,TRUE表示有线程在执行;FALSE表示没有线程执行,可以进入
{
while (data.CriticalRegion.CriticalRegionControl == false)//轮询等待另一个线程执行完成
{
Thread.Sleep(500);
}
lock (data.CriticalRegion)//互斥锁,当加锁时,另外的线程不能读data.N及修改
{
//int n = Convert.ToInt32(data.N) + 1;
data.CriticalRegion.CriticalRegionControl = true;
}
Option(A[i]);//执行表操作
data.CriticalRegion.CriticalRegionControl = false;//表示临界区为空,线程可以进入
data.TableA = string.Empty;
}
else
{
lock (data.CriticalRegion)//互斥锁,当加锁时,另外的线程不能读data.N及修改
{
//int n = Convert.ToInt32(data.N) + 1;
data.CriticalRegion.CriticalRegionControl = true;
}
Option(A[i]);//执行表操作
data.CriticalRegion.CriticalRegionControl = false;
data.TableA = string.Empty;//改表名
}
}
else
{
Option(A[i]);//执行操作
data.TableA = string.Empty;//改表名
}
//data.TableA = string.Empty;//改表名
}
}
private void Option(string tableA)
{
Console.WriteLine("A->" + tableA);
}
}
//////////////////////////////////////
/// <summary>
/// 线程B会执行里面的方法
/// </summary>
public class RunB
{
public void Run(object da)
{
ElementA data = (ElementA)da;
string[] B = new string[] { "A", "B", "C", "A", "C", "A", "A", "C" };
//string[] B = new string[] { "D", "A", "f", "c", "v", "er", "ac", "ee", "gb" };
for (int i = 0; i < B.Length; i++)
{

data.TableB = B[i];//改表名
if (data.Signal)//判断两线程是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
{
if (data.CriticalRegion.CriticalRegionControl == true)//判断临界区是否有线程,TRUE表示有线程在执行;FALSE表示没有线程执行,可以进入
{
while (data.CriticalRegion.CriticalRegionControl == false)//轮询等待另一个线程执行完成
{
Thread.Sleep(500);//当临界区有线程在执行,轮询等待
}
lock (data.CriticalRegion)//互斥锁,当加锁时,另外的线程不能data.CriticalRegion及修改
{
data.CriticalRegion.CriticalRegionControl = true;
}
Option(B[i]);//执行表操作
data.CriticalRegion.CriticalRegionControl = false;
data.TableB = null;
}
else
{
lock (data.CriticalRegion)//互斥锁,当加锁时,另外的线程不能data.CriticalRegion修改
{
data.CriticalRegion.CriticalRegionControl = true;
}
Option(B[i]);//执行表操作
data.CriticalRegion.CriticalRegionControl = false;
data.TableB = null;
}
}
else
{
Option(B[i]);//执行表操作
data.TableB = null;
}
//data.TableB = null;//修改表名
}
}
private void Option(string tableB)
{
Console.WriteLine("B->" + tableB);
}

}

///////////////////////////////////////
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Thread
ElementA el = new ElementA();
RunA a = new RunA();
RunB b = new RunB();
Thread ta = new Thread(new ParameterizedThreadStart(a.Run));
Thread tb = new Thread(new ParameterizedThreadStart(b.Run));
ta.Start(el);
tb.Start(el);

}
}
}

本来我开始考虑是,不管A,B线程,只要针对表操作,就把另外线程挂起,这样可以很方便,但效率很低,没有突出多线程的优点,所以,后来改成了上面的Demo的方式。
请高手多多指点。谢谢。


...全文
115 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
panwen516 2009-07-15
  • 打赏
  • 举报
回复
这个想法是我老大想出来的,他觉得方便。我们用起来很麻烦,而且还是多线程操作的。唉~~~~~~~~~~
我也很无语呀。
Deltag1984 2009-07-09
  • 打赏
  • 举报
回复
向多张表写数据可以用事务来实现啊,为什么要用触发器阿。触发器有很多缺点的,效率低下只是其中一点,貌似哪本书上还说,触发器要到sql事务结束以后才会运行,这个很麻烦啊。
haonanxxx 2009-07-09
  • 打赏
  • 举报
回复
顶。
panwen516 2009-07-09
  • 打赏
  • 举报
回复
我将上面的改过来了,但是我认为理论上还是有问题的。大家先看代码


//////////////////////////////////////////////////
/// <summary>
/// 线程A会执行里面的方法
/// </summary>
public class RunA
{
public void Run(object da)
{
while (true)
{
ElementA data = (ElementA)da;
string[] A = new string[] { "A", "B", "C", "A", "C", "A", "A", "C" };//模拟的数据
for (int i = 0; i < A.Length; i++)
{

data.TableA = A[i];//改表名
if (data.Signal)//判断两线程是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
{
lock (data)
{
Option(A[i]);
data.TableA = string.Empty;
}
}
else
{
Option(A[i]);//执行操作
data.TableA = string.Empty;//改表名
}
//data.TableA = string.Empty;//改表名
}
}
}
private void Option(string tableA)
{
Console.WriteLine("A->写入表" + tableA);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 线程B会执行里面的方法
/// </summary>
public class RunB
{
public void Run(object da)
{
while (true)
{
ElementA data = (ElementA)da;
string[] B = new string[] { "A", "B", "C", "A", "C", "A", "A", "C" };
//string[] B = new string[] { "D", "A", "f", "c", "v", "er", "ac", "ee", "gb" };
for (int i = 0; i < B.Length; i++)
{

data.TableB = B[i];//改表名
if (data.Signal)//判断两线程是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
{

lock (data)
{
Option(B[i]);
data.TableB = null;
}
}
else
{
Option(B[i]);//执行表操作
data.TableB = null;
}
//data.TableB = null;//修改表名
}
}
}
private void Option(string tableB)
{
Console.WriteLine("BBBBB->关闭触发器"+tableB);
Console.WriteLine("BBBBB->写入" + tableB);
Console.WriteLine("BBBBB->开启触发器"+tableB);
}

}
//////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 两线程实现同步数据类
/// </summary>
public class ElementA
{
static string tableA = string.Empty;//A表名
static string tableB = null;//B表名
static bool signal = false;//是否需要同步

//static CriticalRegion cr = new CriticalRegion();//临界区
/// <summary>
/// A表名
/// </summary>
public string TableA
{
set
{
tableA = value;
if (tableA == tableB)
signal = true;
else
signal = false;
}
}
/// <summary>
/// B表名
/// </summary>
public string TableB
{
set
{
tableB = value;
if (tableB == tableA)
signal = true;
else
signal = false;
}
}
/// <summary>
/// 是否需要同步,TRUE表示需要同步,FALSE表示不需要同步
/// </summary>
public bool Signal
{
get { return signal; }
}

}
//////////////////////////////////////////////////////////////////////////////
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Thread
ElementA el = new ElementA();
RunA a = new RunA();
RunB b = new RunB();
Thread ta = new Thread(new ParameterizedThreadStart(a.Run));
Thread tb = new Thread(new ParameterizedThreadStart(b.Run));
ta.Start(el);
tb.Start(el);

}
}
}

但我认为在理论上还是有问题,如
当B线程进入操作(状态为异步),关闭了触发器;这时A线程修改了表名,状态为同步,A线程会对表进行写操作,但这时为同步,按流程来说这是不对的。我上面的写法不能解决这个问题,但运行结果又没有出现B线程对同一张表关闭触发器后,A线程写入同一张表的情况。为什么呢?难道我的理论是错的吗?

高手指点。。。。。。。。。。。。。。。。。
觉得分不够,可以跟我要的。分不是问题
十八道胡同 2009-07-08
  • 打赏
  • 举报
回复
up

110,537

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧