读书人

c#多线程有关问题-求大侠指教

发布时间: 2012-03-30 17:32:09 作者: rapoo

c#多线程问题-求大侠指教!
如下代码为一个创建主键的类 但是测试多线程时锁失败了 求大侠指教!

C# code
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 ) */


[解决办法]
别这么玩了吧 让sp哥看到了 又开骂了
明显是多线程却又要用互斥量 不知道图了个啥
[解决办法]
C# code
 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();
}
}
[解决办法]

探讨

InterLocked 是以原子方式递增变量,但是这个是单例 全局应用中只有一个对象 只在递增的时候保证线程安全,当原子操作完成以后。其它对象将该变量重置或以原子方式执行递增同样会生成数据重复!

引用:

你这个生成ID的用InterLocked的静态方法就可以解决了。
还有个不是很明确datatable.rows.add这个方法是线程安全的……

[解决办法]
探讨
InterLocked 是以原子方式递增变量,但是这个是单例 全局应用中只有一个对象 只在递增的时候保证线程安全,当原子操作完成以后。其它对象将该变量重置或以原子方式执行递增同样会生成数据重复!


引用:

你这个生成ID的用InterLocked的静态方法就可以解决了。
还有个不是很明确datatable.rows.add这个方法是线程安全的么……

[解决办法]
探讨
只有在KeyGen.objKeyGen.ToString()是才会锁 而且整个程序中只有这一个地方是外部访问的!
现在的问题不是死锁 而是根本没有锁 因为生成的数据重复率过高!

[解决办法]
执行完等待一下,看看到底锁了没有
[解决办法]
好吧 还是觉得创建对象那块可能问题
创建那块没有锁的话 ,你的代码中
C# code
  for (int j = 0; j < 100; j++)                    {                        DataRow dr=dtKey.NewRow();                        dr[0] = KeyGen.objKeyGen.ToString();//实际上并发的调用了你的静态                                                                     //构造                        dr[1] = obj;                        dtKey.Rows.Add(dr);                    }
[解决办法]
我上述的前提还有一个就是你的系统只能跑一个,并发的多个,那就更麻烦了

读书人网 >C#

热点推荐