Проблемы с потоками в SQL и C #, когда разные потоки получают одинаковое число, но не должны - PullRequest
0 голосов
/ 18 августа 2010

Мой сценарий: n количество записей в таблице, потоки пытаются получить доступ к таблице. Один должен получить первый номер и удалить его, другие должны получить второй, третий и т. Д. Один за другим.

Но проблема в том, что некоторые потоки получают одинаковое число. Как мне избежать этого?

Мой код:

private void Form1_Load(object sender, EventArgs e)
{
    for (int j = 1; j >= 10; j++)
    {
        Thread.Sleep(1000);
        ThreadStart StarterCon = delegate { this.Start_new(sno); };
        Thread th = new Thread(StarterCon);
        th.Start();
    }
}

private void Start_new(int h)
{
    try
    {
        for (; ; )
        {
            using (SqlConnection ObjConn = new SqlConnection(ConnectionString))
            {
                ObjConn.Open();
                using (SqlDataAdapter ObjAda = new SqlDataAdapter("Select_BlockedNubmer", ObjConn))
                {
                    ObjAda.SelectCommand.CommandType = CommandType.StoredProcedure;
                    SqlParameter parm;

                    parm = ObjAda.SelectCommand.Parameters.Add("@id", SqlDbType.NVarChar);
                    parm.Value = h;
                    using (DataTable dtTable = new DataTable())
                    {
                        ObjAda.Fill(dtTable);
                    }
                }

                ObjConn.Close();
            }
            Thread.Sleep(500);
        }
    }
    catch { }
}

Моя хранимая процедура

Create procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
    set rowcount 1
    select * from BlockedNumber
    delete from BlockedNumber
    set rowcount 0
end

Редактировать: я пробовал следующую хранимую процедуру. Он работает нормально, но чтение числа очень и очень медленно:

ALTER procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin transaction
set rowcount 1
select * from BlockedNumber
delete from BlockedNumber
set rowcount 0
commit transaction
end

Ответы [ 2 ]

1 голос
/ 18 августа 2010

Вы должны использовать транзакции базы данных :

Create procedure [dbo].[Select_BlockedNubmer]
@id varchar(max)
as
begin
    begin transaction
    set rowcount 1
    select * from BlockedNumber
    delete from BlockedNumber
    set rowcount 0
    commit transaction
end

Транзакция гарантирует, что два потока не смогут получить доступ к «промежуточному» состоянию данных.Представьте, что вы тема X: вы выбираете номер.Как только вы это сделаете, номер принадлежит вам, и никакой другой поток не сможет его прочитать.Все остальные потоки должны ждать, пока вы совершите транзакцию, прежде чем они смогут прочитать свои.Это дает вам возможность удалить номер до совершения транзакции, чтобы его не увидели.

0 голосов
/ 18 августа 2010

Вы зациклены навсегда.Внутри этого цикла вы неоднократно выполняете некоторые очень дорогие операции, которые могут привести к слишком большому количеству соединений или другим странным вещам, плавающим вокруг.

Я предлагаю: создать только один SqlConnection объект.Не делайте петли каждые 0,5 секунды, но вместо этого либо делайте петлю медленнее, либо реагируйте на внешний триггер.Вы также можете повторно использовать свой объект SqlDataAdapter для повышения производительности.

Что касается потоков, либо используйте lock, либо используйте другие примитивы синхронизации для предотвращения условий гонки.Хотя отдельные статические методы в используемых библиотечных методах являются поточно-ориентированными, это не означает, что между вызовами к ним потоки мешают вашим объектам данных.код потоков был запутан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...