Critical Sections

Started by
7 comments, last by WebsiteWill 20 years, 8 months ago
Information on these is sketchy. I have a queue as a private member of my class. Internal member functions can pop items from the queue, examine its size, etc. There might be multiple threads dealing with this queue at the same time so I will obviously need a critical section, or mutex, in the class in order to lock it as necessary. Outside of the class, the user can only push items onto the queue. Now, I will obviously need to lock the queue here also so that the threads can''t access it while I am pushing onto it. I don''t want global critical sections so I am thinking that I could add member functions to acquire the critical section and release it as necessary. Something like this

class Net
{
   private:
      queue<int> myQueue;
      CRITICAL_SECTION myCS;
      void DoStuffToQueue
   public:
      void AddToQueue(int myInt);
      void GetCriticalSection;
      void ReleaseCriticalSection;
};
Now internally, I can call my functions to get and release the critical section when I need to lock the queue but is this also valid outside in a main program? Can I do something like this

int main()
{
   Net myNet;
   GetCriticalSection();
   AddToQueue(6);
   ReleaseCriticalSection();
   return 0;
}
It compiles nicely so far but I''m wondering if it is actually functioning they way it seems to be. Code above is pseudo of course, function names, return types and parameters are quite different in the actual code. Thanks for any input, Webby
Advertisement
Sure, that looks fine so far. However, consider having mutex objects instead of a single set of functions; that''ll allow you to have different "kinds" of critical sections for when you have something other than your queue that requires one.

How appropriate. You fight like a cow.
I'll admit to being a complete nube when it comes to threads. I'll have to scour to find info in mutexes and crit_secs. I seem to remember reading that the overhead for using crit_secs was lower that mutexes when used on Linux. I could be mistaken. I will certainly look into that.

EDIT* So a crit_sec can only lock one set of data? It's no biggy to make extra crit_secs as necessary but I was hoping to just use a single crit_sec for all of my protectional needs.

Webby

[edited by - websitewill on August 12, 2003 10:46:39 AM]
You can have more than one critical section. Each critical section is responsible for protecting a particular group of resource. So anyone trying to access that resource group will need to acquire the crit_sec first. If it has been acquired by someone else, then he/she will have to wait until the owner frees it.


Critical Section operates within user mode (when no one is fighting for it ) while Mutex operates on Kernel level always.

Since your programs are normally in user mode, switching back and forth from user to kernel mode has slightly more overhead.

But critical section is local to a process while mutex can be system wide (cross processes).


hmm... I think Unixes/Linuxes don''t have critical section... I might be wrong.
"after many years of singularity, i'm still searching on the event horizon"
You should also consider removing the GetCS() and RemoveCS() methods from the public interface, and instead call them from inside AddToQueue().
This will reduce the risk that some user of the Net class forgets to take or release the semaphore in the intended way. It is also nice to hide implementation-details such as this from the users of the class.

-p
Yeah, I caught that one earlier AP. It all seems to be working quite well. Now I''m down to another bug (hopefully the last for this part). Can anyone see anything wrong with this code? When I run the program this is making it shut down.
struct sockaddr_in toAddress;		toAddress.sin_family = AF_INET;toAddress.sin_port = htons(myPacket1->iToPort);toAddress.sin_addr.s_addr = inet_addr("192.168.000.001);memset(&(toAddress.sin_zero), ''\0'', 8);int iBytesSent = 0;int iSize = myPacket1->SizeOfData();char* cpsInfo = (char*)&myPacket1->sInfo;while (iBytesSent < iSize{    iBytesSent = iBytesSent+1 + sendto(iSocket, cpsInfo,				iSize				0, (struct sockaddr*)&toAddress,				sizeof(toAddress));}cout << "Just sent " << iBytesSent << " of "      << iSize << " bytes" << endl;


Specifically, it is the call to sendto that is generating the error. I included the rest in case I wasn''t setting up the structure correctly or something.

Thanks for any help,
Webby

PS. Has anyone else been having trouble accessing Gamedev lately? Seems like ever couple of tries i get the "Page Not Responding" error page. Thought it might just be my connection but it seems like I can browse my other usual sites (and others) just fine.
Uh, if it doesn''t work properly your first inclination should be to check the return codes and either look up the code on MSDN or pass it to ::FormatMessage().
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
In posix term, the code between the mutex lock and unlock is called a critical section . This is the code that must be syncronized.

On Win32 there is both a kernel object called Mutex and CrticalSection. A Win32 CriticalSection is a process-local mutex. Normal mutexes are system-wide, meaning multiple processes can syncronize using the same mutex. CriticalSections can only be used to syncronize threads in the same process.

If you''re programming in C++, you want to use the scoped guard idiom to lock and unlock the mutex. This makes the compiler produce exception-safe code and handles the (un)locking more automatically.

Also, on Win32 Mutexes and CriticalSections are recursive by default, meaning you can lock and unlock them more than once from the same thread and everything works OK. With posix this is supported as a non-portable extention and must be explicitly enabled.

It''s feasible for a *nix to provide a process-local mutex, but don''t bet on it. After you write threaded (and socket) code for Win32, you''ll wonder how they make anything work in the *nix world (or at least I do).

ACE is a cross-platform socket & thread toolkit, though I''ve only used the socket portion of it (there''s a bunch of ORB crap too).



- Magmai Kai Holmlor

"No, his mind is not for rent to any god nor government" - Rush, Tom Sawyer

[Look for information | GDNet Start Here | GDNet Search Tool | GDNet FAQ | MSDN RTF[L] | SGI STL Docs | STFW | Asking Smart Questions ]

[Free C++ Libraries | Boost | ACE | Loki | MTL | Blitz++ | wxWindows| Spirit(xBNF)]
[Free C Libraries | zlib ]

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:Original post by Magmai Kai Holmlor
In posix term, the code between the mutex lock and unlock is called a critical section . This is the code that must be syncronized.

It''s feasible for a *nix to provide a process-local mutex, but don''t bet on it. After you write threaded (and socket) code for Win32, you''ll wonder how they make anything work in the *nix world (or at least I do).



It''s actually rather easy to write your own mutex code with a tiny bit of assembly...using the BTS instruction.

Two functions from my ''Mutex'' class:

void Mutex::Lock( void ){	register unsigned char rtn;	do	{		asm ("bts %1, %0" : "+r" (LockData) : "r" (0) );		asm ("setc %0" : "+r" (rtn) );	} while ( rtn ); //loops until we aquire the mutex}void Mutex::Unlock( void ){	LockData = 0;} 


I only call these from my lock class, which locks and unlocks as it constructs and destructs.

LockData is an integer in my code... I''m assuming a char would work fine.

If you want to squeese as much space out as possible, it''s possible to have a mutex for every bit of the char/int/whatever. All that needs changing is a single parameter, the "r" (0) part. This selects the first bit... to select the second, you''d place "r" (1). The third would be "r" (2) and so forth...

BTS sets the bit and places the original value in the carry bit in an atomic action. the second instruction (setc) saves the original result to the rtn variable, so we can see if we got the mutex. If it''s 1, then no, it was allready being used, and thus setting it to 1 didn''t do anything. If it''s 0, then we just set it to 1, and it''s our mutex now. Muahahahahha!

ok...ill shutup now....

This topic is closed to new replies.

Advertisement