c#多线程问题-求大侠指教!
如下代码为一个创建主键的类 但是测试多线程时锁失败了 求大侠指教!
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Data;using System.Data.SqlClient;namespace ConsoleUI{ class Program { public class KeyGen { private string Scale=""; private Int32 Mete = 0; private static KeyGen m_objKeyGen; private KeyGen() { } public static KeyGen objKeyGen { get { if (m_objKeyGen == null) { m_objKeyGen = new KeyGen(); } return m_objKeyGen; } } public override string ToString() { lock (this) { DateTime now = DateTime.Now; string strNow = now.ToString("HHmmssffffzzz"); if (Scale.CompareTo(strNow)!=0) { Mete = 0; Scale = strNow; } else { ++Mete; } return string.Format("{0}{1:0000}", now.ToString("yyyyMMddHHmmssfff"), Mete); } } } static void Main(string[] args) { DataTable dtKey = new DataTable(); dtKey.Columns.Add("TKEY", typeof(string)); dtKey.Columns.Add("THID", typeof(int)); KeyGen objkey = KeyGen.objKeyGen; Thread[] thr=new Thread[100]; for (int i = 0; i < 100; i++) { thr[i] = new Thread(delegate(object obj) { for (int j = 0; j < 100; j++) { DataRow dr=dtKey.NewRow(); dr[0] = KeyGen.objKeyGen.ToString(); dr[1] = obj; dtKey.Rows.Add(dr); } }); } for (int i = 0; i < 100; i++) { thr[i].Start(i); } new Thread(delegate() { while (true) { Thread.Sleep(1000); bool IsAllFull = true; for (int i = 0; i < thr.Length; i++) { if (thr[i].ThreadState != ThreadState.Stopped) { IsAllFull = false; break; } } if (IsAllFull) { break; } } using (SqlBulkCopy sbc=new SqlBulkCopy(@"server=.\sqlexpress;uid=sa;pwd=;database=TESTDB;")) { sbc.BatchSize = 1000; sbc.DestinationTableName = "T_Key"; sbc.ColumnMappings.Add("TKEY", "TKEY"); sbc.ColumnMappings.Add("THID", "THID"); sbc.WriteToServer(dtKey); } Console.WriteLine("保存数据完成"); }).Start(); } }}/* CREATE DATABASE TESTDB GO USE TESTDB GO CREATE TABLE T_Key ( TKEY varchar(30), THID int ) */
public static KeyGen objKeyGen { get { if (m_objKeyGen == null) { lock (this)//有可能是新建的时候没有加锁 造成的 还是那句话 最好别这么 //玩 { m_objKeyGen = new KeyGen(); } } return m_objKeyGen; } }
[解决办法]
你这个生成ID的用InterLocked的静态方法就可以解决了。
还有个不是很明确datatable.rows.add这个方法是线程安全的么
另,你只用一个线程加100条数据这个貌似有些过了,估计程序在线程切换上的消耗算上的话比单线程还要差点吧
[解决办法]
我也想知道怎么做,支持一下
[解决办法]
死锁在循环中因为前后两次访问dtKey而发生。
for (int j = 0; j < 100; j++)
{
DataRow dr=dtKey.NewRow(); // 第一次访问
dr[0] = KeyGen.objKeyGen.ToString();
dr[1] = obj;
dtKey.Rows.Add(dr); // 第二次访问
}
[解决办法]
class Program
{
public class KeyGen
{
public static Object Locker = new object();
private string Scale = "";
private Int32 Mete = 0;
private static KeyGen m_objKeyGen;
private KeyGen() { }
static KeyGen() { m_objKeyGen = new KeyGen(); }
//public static KeyGen objKeyGen
//{
// get
// {
// if (m_objKeyGen == null)
// {
// m_objKeyGen = new KeyGen();
// }
// return m_objKeyGen;
// }
//}
public static KeyGen objKeyGen { get { return m_objKeyGen; } }
public override string ToString()
{
lock (this)
{
DateTime now = DateTime.Now;
string strNow = now.ToString("HHmmssffffzzz");
if (Scale.CompareTo(strNow) != 0)
{
Mete = 0;
Scale = strNow;
}
else
{
++Mete;
}
return string.Format("{0}{1:0000}", now.ToString("yyyyMMddHHmmssfff"), Mete);
}
}
}
static void Main(string[] args)
{
DataTable dtKey = new DataTable();
dtKey.Columns.Add("TKEY", typeof(string));
dtKey.Columns.Add("THID", typeof(int));
KeyGen objkey = KeyGen.objKeyGen;
Thread[] thr = new Thread[100];
for (int i = 0; i < 100; i++)
{
thr[i] = new Thread(delegate(object obj)
{
for (int j = 0; j < 100; j++)
{
DataRow dr = null;
lock (KeyGen.Locker) { dr = dtKey.NewRow(); }
dr[0] = KeyGen.objKeyGen.ToString();
dr[1] = obj;
lock (KeyGen.Locker) { dtKey.Rows.Add(dr); }
}
});
}
for (int i = 0; i < 100; i++)
{
thr[i].Start(i);
}
new Thread(delegate()
{
while (true)
{
Thread.Sleep(1000);
bool IsAllFull = true;
for (int i = 0; i < thr.Length; i++)
{
if (thr[i].ThreadState != ThreadState.Stopped)
{
IsAllFull = false;
break;
}
}
if (IsAllFull)
{
break;
}
}
//using (SqlBulkCopy sbc = new SqlBulkCopy(@"server=.\sqlexpress;uid=sa;pwd=;database=TESTDB;"))
//{
// sbc.BatchSize = 1000;
// sbc.DestinationTableName = "T_Key";
// sbc.ColumnMappings.Add("TKEY", "TKEY");
// sbc.ColumnMappings.Add("THID", "THID");
// sbc.WriteToServer(dtKey);
//}
Console.WriteLine("保存数据完成");
}).Start();
}
}
[解决办法]
for (int j = 0; j < 100; j++) { DataRow dr=dtKey.NewRow(); dr[0] = KeyGen.objKeyGen.ToString();//实际上并发的调用了你的静态 //构造 dr[1] = obj; dtKey.Rows.Add(dr); }
[解决办法]
我上述的前提还有一个就是你的系统只能跑一个,并发的多个,那就更麻烦了