Cheat Sheet
Visual Studio debugging might not always be helpful or it might not always be available.
Sometimes when you want to take a quick look at what's wrong, saying c:\debuggers\cdb -pn
The ramblings of a disgruntled geek!!
Reminder to self:
ThreadStaticAttribute only works with static fields!
Here is why:
public class TestingTLS
{
[ThreadStatic]
public static int value = 0;
[ThreadStatic]
public int value2 = 0;
}
public class MyClass
{
public static void TLSTest()
{
TestingTLS tls = new TestingTLS();
Dictionary<int, Thread> threads = new Dictionary<int, Thread>();
Semaphore sem = new Semaphore(100, 100);
long count = 0;
for ( int i = 0 ; i < 100 ; i ++ )
{
Thread t = new Thread(state => {
int tid = Thread.CurrentThread.ManagedThreadId;
TestingTLS.value = tid;
Thread.Sleep(0);
if ( tid != TestingTLS.value )
{
Console.Error.WriteLine( "Value 1: {0} read {1}", tid, TestingTLS.value );
Interlocked.Increment(ref count);
}
tls.value2 = tid;
Thread.Sleep(0);
if ( tid != tls.value2 )
{
Console.Error.WriteLine( "Value 2: {0} read {1}", tid, tls.value2);
Interlocked.Increment(ref count);
}
threads.Remove(tid);
if ( threads.Count == 0 )
sem.Release();
});
threads.Add(t.ManagedThreadId, t);
sem.WaitOne();
t.Start();
}
Console.WriteLine("Waiting for all threads to finish...");
sem.WaitOne();
Console.WriteLine("Total races: " + count);
}
}
You will see races for value2 but not for value.
Update: The code snippet was updated, since the previous example had a race where the Total Race count would reach before all threads have finished reporting the wrong number of total races in cases where there were large number of races.
#include "stdafx.h"
#include <intrin.h>
#include <process.h>
#include <vector>
#include <utility>
#include <algorithm>
#include <iostream>
#pragma intrinsic (_InterlockedCompareExchange, _InterlockedExchange)
namespace DotFermion
{
class CCriticalSection
{
enum { LOCK_IS_FREE = 0, LOCK_IS_TAKEN = 1 };
private:
long lock;
long ownerThreadId;
long acquireCount;
public:
CCriticalSection():
lock(LOCK_IS_FREE),ownerThreadId(-1),acquireCount(0){}
~CCriticalSection()
{
Release();
}
//Non-recursive Acquire. Once its called, all threads, even the one owning the lock block on this lock.
//Even a subsequent AcquireRecursive call after this one blocks.
void Acquire()
{
while (_InterlockedExchange(&lock, LOCK_IS_TAKEN) == LOCK_IS_TAKEN);
}
//Recursive Acquire. It doesn't block if called multiple times from the same thread.
void AcquireRecursive(long threadId)
{
if(ownerThreadId != -1 && threadId == ownerThreadId)
{
_InterlockedIncrement(&acquireCount);
return;
}
Acquire ();
_InterlockedExchange(&ownerThreadId, threadId );
_InterlockedIncrement(&acquireCount);
}
void Release()
{
if(acquireCount > 1)
{
_InterlockedDecrement(&acquireCount);
return;
}
_InterlockedExchange(&acquireCount, 0);
_InterlockedExchange(&ownerThreadId, -1);
_InterlockedExchange(&lock, LOCK_IS_FREE);
}
};
}
#define LIST_POS = 4;
#define INDEX_POS = 8;
typedef void (*LPFNTHREADPROC) (void*);
typedef std::vector<uintptr_t> THREADLIST;
typedef THREADLIST* PTHREADLIST;
typedef struct _args_t
{
DotFermion::CCriticalSection* pCs;
PTHREADLIST pThreadList;
int index;
} args_t;
THREADLIST g_ThreadList;
int g_ThreadCount = 0;
int g_SharedCounter = 0;
void ThreadProc(void* argList)
{
args_t* args = (args_t*)argList;
args->pCs->AcquireRecursive((long)args->pThreadList->at(args->index));
g_SharedCounter++;
args->pCs->AcquireRecursive((long)args->pThreadList->at(args->index));
g_SharedCounter++;
args->pCs->Release();
args->pThreadList->at(args->index) = -1L;
g_ThreadCount--;
args->pCs->Release();
delete args;
}
int StartThreads ( int n, PTHREADLIST pThreadList, DotFermion::CCriticalSection* cs )
{
pThreadList->resize(n);
for ( int i = 0 ; i < n ; i ++ )
{
args_t* args = new args_t;
if ( args == NULL ) continue;
args->pCs = cs;
args->pThreadList = pThreadList;
args->index = i;
uintptr_t threadId = _beginthread(ThreadProc, 0, (void*)args);
if ( threadId != -1L )
{
cs->Acquire();
pThreadList->at(i) = threadId;
g_ThreadCount ++;
cs->Release();
}
}
return g_ThreadCount;
}
void Join (int* threadCount)
{
while ( *threadCount );
}
int _tmain(int argc, _TCHAR* argv[])
{
DotFermion::CCriticalSection cs;
StartThreads(100, &g_ThreadList, &cs);
Join(&g_ThreadCount);
std::cout << g_SharedCounter << std::endl;
return 0;
}
I finally figured it out. It was there right in front of my eyes. I stumbled upon it so many times, but I always missed it.
I have been doing web service development for quite some time now. These services are part of pretty complex systems that require a long time to deploy. Imagine, every time there was a build number change and I wanted to modify one of the services. I wrote the code, built it, deployed the services (this step was the longest and most painful), got the wsdl, generated the proxy and updated and built again. The reason it required full redeployment on build number changes is that the assemblies are bound by strong names. It was one heck of a time consuming job. All this work, just to update the proxy; WSDL generation required a live service. :)
Though I still have to do this to verify that the code that I wrote actually works, proxy generation is not that much of a hassle, especially when I am writing code that I know works already and there is minimal need to try it out.
This time has been drastically reduced. Thanks to System.Web.Services.Description.
ServiceDescriptionReflector.
The GetWsdl tool is here. I will publish it soon. Stay tuned.
-UG
http://scrapzilla.blogspot.com/2007/11/remember-remember_7668.html
A picture (and a good line) is worth a million words.
Update: There was a picture of masks (the ones worn by revolutionaries in Vendetta) stored inside a fire extinguisher container with a hammer by its side saying, “In case of revolution, break glass”. Below the picture, it says: “And the hammer hangs on”.
Update 2: Here is the original picture :)
The finals start from Sunday November 11, 2007. The first quarter has ended. Phew J
Microsoft ? Me ? No! it cant be like that !! That was the first question I asked for atleast one week when I got up !! It all happened in a snap and I never knew. It all started with a phone interview and the next thing I knew was a congratulations email from Microsoft telling me that I was hired.
It all started like this:
One of my friends sent me an email about Microsoft coming to Dubai to hire Pakistanis. I did not send my CV at first. But then a friend of mine sent his CV, and he got a phone interview. I sent my CV somewhere near the end of January, and got a phone interview in a couple of days. That was unbelievable. It was a lady named Priya, who emailed me and then took my phone interview. That interview was one heck of an experience for me. I thought I had a terrible interview and I never saw myself clearing that one. I got all the technical questions right, but I failed the IQ question. And as I had heard, the IQ question was the decider, which was wrong. In a week I got an email inviting me to Dubai for in-person interviews. This was the beginning of a very long and painful process....
To be continued...
This is the home of king of COM, Chris Sells. Also has some stuff related to MS interviews.
Home of the founder of FogCreek software and the former Program Manager of the Excel team, Joel Spolsky.
Also see the archive for some interesting articles by Joel.
The blog maintained by Raymond Chen, the Windows guru. It has some very interesting articles on Windows history.