-1

I wonder how to define a class properly and use it safely. I mean thread safely when thousands of concurrent calls are being made by every website visitor.

I made myself something like below but i wonder is it properly built

public static class csPublicFunctions
{
    private static Dictionary<string, clsUserTitles> dicAuthorities;

    static csPublicFunctions()
    {
        dicAuthorities = new Dictionary<string, clsUserTitles>();
        using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
        {
            foreach (DataRow drw in dtTemp.Rows)
            {
                clsUserTitles tempCLS = new clsUserTitles();
                tempCLS.irAuthorityLevel = Int32.Parse(drw["Level"].ToString());
                tempCLS.srTitle_tr = drw["Title_tr"].ToString();
                tempCLS.srTitle_en = drw["Title_en"].ToString();
                dicAuthorities.Add(drw["authorityLevel"].ToString(), tempCLS);
            }
        }
    }

    public class clsUserTitles
    {
        private string Title_tr;
        public string srTitle_tr
        {
            get { return Title_tr; }
            set { Title_tr = value; }
        }

        private string Title_en;
        public string srTitle_en
        {
            get { return Title_en; }
            set { Title_en = value; }
        }

        private int AuthorityLevel;
        public int irAuthorityLevel
        {
            get { return AuthorityLevel; }
            set { AuthorityLevel = value; }
        }
    }

    public static clsUserTitles returnUserTitles(string srUserAuthority)
    {
        return dicAuthorities[srUserAuthority];
    }
}

Dictionary will be initialized only 1 time. No add remove update later.

Charles
  • 50,943
  • 13
  • 104
  • 142
Furkan Gözükara
  • 22,964
  • 77
  • 205
  • 342
  • 3
    Your naming is extremely wrong. Don't use Hungarian notation. Don't use underscores. Do use UpperCamelCase. – SLaks Jan 10 '13 at 22:20
  • @SLaks thanks for suggestion. Can you explain why this is wrong ? – Furkan Gözükara Jan 10 '13 at 22:21
  • What kind of actions you would like to make thread-safe? – Alexander Balte Jan 10 '13 at 22:23
  • @MonsterMMORPG - It's not *technically* wrong. Your code won't stop working or anything, but it is the preferred style. – System Down Jan 10 '13 at 22:24
  • 2
    you have created a static class which contains the static dictionary. How are you going to use it? from my point of view, creating static objects in ASP.NET isn't a good idea at all and it is better to avoid using them. – platon Jan 10 '13 at 22:26
  • 1
    Side note: if you feel that making a statement bold makes it true why not to state "this code is threadsafe" in bold and done with it :)... Since you did not show initialization code itself noone can make assumption if it is indeed correctly called once. – Alexei Levenkov Jan 10 '13 at 22:56
  • @AlexeiLevenkov how is this not being initialization ? i don't initialize anywhere else. This is the whole class. I call function as csPublicFunctions.returnUserTitles(myString); – Furkan Gözükara Jan 11 '13 at 01:37
  • I missed the fact that csPublicFunctions is name of the class and static constructor... And Now looking through your sample and while carefully ignoring I think it looks much more ok than I thought originally. – Alexei Levenkov Jan 11 '13 at 03:04
  • @MonsterMMORPG: http://msdn.microsoft.com/en-us/library/vstudio/ms229043.aspx – SLaks Jan 11 '13 at 16:47

6 Answers6

3

A quick look through your code and it seems to me that your first problem will be the publicly available dictionary dicAuthorities. Dictionaries are not thread safe. Depending on what you want to do with that Dictionary, you'll need to implement something that regulates access to it. See this related question:

Making dictionary access thread-safe?

Community
  • 1
  • 1
System Down
  • 6,192
  • 1
  • 30
  • 34
  • yes i made it private. it will be one time initialized at first call right? – Furkan Gözükara Jan 10 '13 at 22:30
  • @MonsterMMORPG - Even if you make it private, you are still accessing it from public static methods. So it's still not thread safe. – System Down Jan 10 '13 at 22:31
  • @MonsterMMORPG - If it's going to be read-only after initialization, then that's thread safe. However, you need to be careful on how you initialize it, so that you can guarantee that it's done only once. – System Down Jan 10 '13 at 22:36
  • Now won't the above class init it only 1 time ? As far as i know static class constructors are called 1 time only at first call am i wrong ? – Furkan Gözükara Jan 10 '13 at 22:39
  • @SystemDown Barring few specific scenarios (e.g. inheritance of singleton classes) using static classes gets the job done just the same, with much less hassle. – SWeko Jan 10 '13 at 22:45
  • @MonsterMMORPG - True enough. I'm just paranoid when it comes to static *anything* lol. – System Down Jan 10 '13 at 22:45
  • do you know how can i make it initialized only 1 time ? – Furkan Gözükara Jan 10 '13 at 22:46
  • @MonsterMMORPG - Like I said, Google "singleton design pattern" and you'll find plenty of code. It's pretty easy stuff. – System Down Jan 10 '13 at 22:49
  • i think you know incorrect. according to the answer of @Jon Skeet my implementation is thread safe : http://stackoverflow.com/questions/7059018/in-c-sharp-does-static-constructor-run-for-each-initialization-of-object-or-onl – Furkan Gözükara Jan 10 '13 at 22:53
  • @MonsterMMORPG - Like I said, I prefer to be paranoid when it comes to static classes and thread safety. And implementing a singleton pattern is very easy (it's only a couple of loc), so why not? – System Down Jan 10 '13 at 23:24
  • oh i see. i don't like being paranoid and this is not very crucial :) – Furkan Gözükara Jan 11 '13 at 01:37
  • @MonsterMMORPG - Well in my case, when I first started programming .NET, I abused static classes (because I didn't really understand them then) and was awarded by massive amounts of bugs and headaches. – System Down Jan 11 '13 at 17:25
3

Dictionary supports thread safe reading. Here is the proof from MSDN:

A Dictionary can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

So, if you are planning to only read data from it, it should work. However, I do not believe that your dictionary is filled only once and won't be modified during your application work. in this case, all other guys in this thread are correct, it is necessary to synchronize access to this dictionary and it is best to use the ConcurrentDictionary object.

Now, I want to say a couple of words about the design itself. If you want to store a shared data between users, use ASP.NET Cache instead which was designed for such purposes.

platon
  • 5,310
  • 1
  • 22
  • 24
  • it will be only 1 time initialized. do you see any code above that will modify dictionary ? – Furkan Gözükara Jan 10 '13 at 22:33
  • 1
    @MonsterMMORPG, heh, you have a public Dictionary, I do not know how you are planning to use it and whether it can be modified by other code or not... But, from my point of view, Cache - is the best solution. – platon Jan 10 '13 at 22:44
  • do you know how can i make this construct runs only 1 time so only 1 time initialization. And no other than returnUserTitles function ever touches that dictionary :) – Furkan Gözükara Jan 10 '13 at 22:45
  • I know:), cache data should be initialized in the Application_Start method. – platon Jan 10 '13 at 22:47
  • if i initialize there how will classes reach those data ? you mean the global.asax file right ? – Furkan Gözükara Jan 10 '13 at 22:51
  • 1
    right, I meant global.asax file. Cache data is shared between all users and can be accessed by a key. I.e. cache works itself like a dictionary. To learn how to use cache, refer to http://msdn.microsoft.com/en-us/library/18c1wd61(v=vs.71).aspx link. – platon Jan 10 '13 at 22:54
  • Static functions and variables are also as far as i know shared between all users ? – Furkan Gözükara Jan 10 '13 at 23:23
  • But Cache allows you to avoid even thinking about thread safety of your class at all. It is a good benefit!!! If you (or any developer from your team) decides to make this dictionary editable, you will have to either change your code to use Concurrent Dictionary, or hide the Dictionary object from your class and add methods to modify and read data from the dictionary (to make access to it threadsafe)... – platon Jan 10 '13 at 23:35
  • ok i see. so as far as nobody touches it is safe right now :) – Furkan Gözükara Jan 10 '13 at 23:48
3

As the others have said, Dictionary<TKey,TValue> is not inherently thread-safe. However, if your usage scenario is:

  1. Fill the dictionary on startup
  2. Use that dictionary as lookup while the application is running
  3. Never add or remove values after startup

than you should be fine.

However, if you use .net 4.5, I would recommend making #3 explict, by using a ReadOnlyDictionary

So, your implementation might look like this (changed the coding style to more C# friendly)

private static readonly ReadOnlyDictionary<string, UserTitles> authorities;

static PublicFunctions()
{
    Dictionary<string, UserTitles> authoritiesFill = new Dictionary<string, clsUserTitles>();
    using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
    {
        foreach (DataRow drw in dtTemp.Rows)
        {
            UserTitles userTitle = new UserTitles
            {
              AuthorityLevel = Int32.Parse(drw["Level"].ToString()),
              TitleTurkish = drw["Title_tr"].ToString();
              TitleEnglish = drw["Title_en"].ToString();
            }
            authoritiesFill.Add(drw["authorityLevel"].ToString(), userTitle);
        }
    }
    authorities = new ReadOnlyDictionary<string, UserTitles>(authoritiesFill);
}

I've also added a readonly modifier to the declaration itself, because this way you can be sure that it won't be replaced at runtime by another dictionary.

SWeko
  • 30,434
  • 10
  • 71
  • 106
  • not moved to 4.5 yet but planning very soon. yes i suppose the above code will initialize only 1 time right ? i am not planning update delete or insert later. – Furkan Gözükara Jan 10 '13 at 22:34
  • It's not too hard to implement it yourself, it just wraps an inner dictionary, and disallows changes to it. – SWeko Jan 10 '13 at 22:42
  • i suppose. @Alexei Levenkov said that it is not thread safe initialized. How can i make it thread safe initialized only 1 time ? – Furkan Gözükara Jan 10 '13 at 22:44
  • Static constructors **are** thread safe, so if your only change is there, you should be fine. – SWeko Jan 10 '13 at 22:46
  • i was knowing that way. but @Alexei Levenkov said it is not thread safe initialized :) his quote : "Initialization is not protected by any locks so you end-up with multiple initializations at the same time" – Furkan Gözükara Jan 10 '13 at 22:47
2

No you code is not thread safe.

  • [EDIT does not apply - set/created inside static constructor] Dictionary (as pointed by System Down answer) is not thread safe while being updated. Dictionary is not read only - hence no way to guarantee that it is not modified over time.
  • [EDIT does not apply - set/created inside static constructor] Initialization is not protected by any locks so you end-up with multiple initializations at the same time
  • Your entries are mutable - so it is very hard to reason if you get consistent value of each entry
  • [EDIT does not apply - only modified in static constructor] Field that holds dictionary not read-only - depending on code you may end-up with inconsistent data if not caching pointer to dictionary itself.

Side note: try to follow coding guidelines for C# and call classes starting with upper case MySpecialClass and have names that reflect purpose of the class (or clearly sample names).

EDIT: most of my points do not apply as the only initialization of the dictionary is inside static constructor. Which makes initialization safe from thread-safety point of view. Note that initialization inside static constructor will happen at non-deterministic moment "before first use". It can lead to unexpected behavior - i.e. when access to DB may use wrong "current" user account.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • @MonsterMMORPG - put proper locking around initialization (to avoid initialization from 2 requests - your "initialized only once" does not feel to be enough of guarantee to me), put initialization code to app startup (may be bad for performance of your site), or simply use Cache as suggested in other answers. – Alexei Levenkov Jan 10 '13 at 22:53
  • according to the @Jon Skeet it is already thread safe. can you check this thread ? http://stackoverflow.com/questions/7059018/in-c-sharp-does-static-constructor-run-for-each-initialization-of-object-or-onl – Furkan Gözükara Jan 10 '13 at 23:17
  • @MonsterMMORPG, you are right - I did not realized that the method is static constructor... so initialization is ok (will eventually cause you pain as it is not deterministic, but safe from threading point of view). – Alexei Levenkov Jan 10 '13 at 23:28
  • @MonsterMMORPG, I've commented most points in my answer as invalid for your case. The only non-safe point is your `clsUserTitles` class as values could be changed by code that obtains it. Making all properties read-only would make it much safe, or you can return copies of the class instead. – Alexei Levenkov Jan 11 '13 at 03:17
0

The answer to your question is no, it's not thread safe. Dictionary is not a thread-safe collection. If you want to use a thread-safe dictionary then use ConcurrentDictionary.

Besides that, it's difficult to say whether your csPublicFunctions is thread-safe or not because it depends on how you handle your database connections inside the call to DbConnection.db_Select_DataTable

Icarus
  • 63,293
  • 14
  • 100
  • 115
0

There is not thread-safe problem only with public Dictionary. Yes, dictionary filling is thread-safe. But another modification of this dictionary is not thread safe. As was wrote above - ConcurrentDictionary could help.

Another problem that your class clsUserTitles is not thread-safe too. If clsUserTitles is using only for reading you could make each property setter of clsUserTitles private. And initialize these properties from clsUserTitles constructor.

Alexander Balte
  • 900
  • 5
  • 11