tags:

views:

102

answers:

2

My scenario: n number of records in table, threads trying to access the table. One has to get first number and delete it, others have to get the second, third, etc., one by one.

But the problem is some of the threads get the same number. How do I avoid this?

My code:

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 { }
}

My stored procedure is

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

Edit: I tried the following stored procedure. It works fine but reading number is very very slow:

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
+1  A: 

You should use database transactions:

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

A transaction ensures that two threads cannot access the “intermediate” state of the data. Imagine you’re thread X: You pick a number. As soon as you do this, the number belongs to you and no other thread can read it. All other threads have to wait for you to commit the transaction before they can read theirs. This gives you a chance to remove the number before committing the transaction, so they won’t see it.

Timwi
i tried this also still the problem is there thank u
@anbuselvanmca: there's more issues in your code than only transactions. See the comments below your original q. and take some time to update your code to reflect your current situation, as this cannot be accurate.
Abel
On SQL2005 and above you don't need to use an explicit transaction: `DELETE TOP(1) FROM BlockedNumber OUTPUT DELETED.*` will do the trick. And with the added bonus that it fixes the broken semantics which mean that your `SELECT` and `DELETE` might refer to different rows since there's no explicit ordering or filtering.
LukeH
A: 

You are looping forever. Inside this loop, you repeatedly do some very expensive operations, that may result in too many connections or other odd stuff floating around.

My suggestion is: create only one SqlConnection object. Do not loop each 0.5 seconds, but instead either loop slower or react to an external trigger. You can also reuse your SqlDataAdapter object for better performance.

With regards to threads, either use lock or use other synchronisation primitives to prevent race conditions. While individual static methods on the used library methods are thread-safe, that doesn't mean that between calls to them, threads interfere with your data objects.

Update: edited, because at first, the threading code was obfuscated.

Abel
@downvoters: care to explain?
Abel
Hm, can’t speak for the downvoters, but to be fair, he doesn’t have connections floating around: he disposes of them appropriately.
Timwi
@Timwi: that is correct, but as you may know, `Dispose` is one thing, but managed resources are not cleared upon disposing, but cleared upon the next GC cycle. Also, setting up an SqlConnection is a very expensive operation that can take tens or hundredths of ms to complete. They don't belong *at all* in the inner loop. Finally, but that's a guess, `SqlConnection` uses pooling internally, which may get totally mixed up when creating hundredths of connections at once, but that's a guess.
Abel
[Hundredths](http://dictionary.reference.com/browse/hundredth)? :)
Timwi
@Timwi: haha, ahum, well, *hundreds* then, tx!
Abel