Daily Archives: February 28, 2014
migration C#, Java, C++ (day 4)
Today we translate some basics of threading and locking. For the ones, who follow the C# hardcore posts, I will cover the C# side in more detail on Tuesday.
Further down I also cover operator overloading today.
Some background info:
Deadlocks
WaitOne
There are no direct equivalents in C++ for the C# lock keyword, the Monitor class and Semaphores unless you are using the .Net Framework on the C++ side. This is clearly not what you want to do. The speed advantage of C++ would end in smoke.
Mutexes do exist for both C# and C++. You have to get used to using Mutexes in C++. They are hardly used in C#, but found often in C++.
The C++ mutex is not the same as the C# Mutex. This is as confusing as using a C# List and think it would be similar to a C++ list.
The C++ mutex is (depite its name) much closer to the C# Monitor class. It definitely is not as public as the C# Mutex, which is known to each process across the entire computer system.
Java looks quite retarded today. We already know that Java does not support pointers. Today it becomes even worse. There is no C# type mutex and no operator overloading.
Lock, Monitor, Semaphore
public void DoSomething() { Console.WriteLine("Good night my dear thread " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } // object lAnyObject2 = new object(); public void LockUsage() { lock (lAnyObject2) { DoSomething(); } } // object lAnyObject1 = new object(); public void MonitorUsage() { bool lLocked = false; try { Monitor.Enter(lAnyObject1, ref lLocked); // using System.Threading; DoSomething(); } finally { if (lLocked) Monitor.Exit(lAnyObject1); } } // // Limits the number of threads that can access a resource or pool of resources concurrently. private static Semaphore _Semaphore = new Semaphore(3, 3); // three objects allowed to access concurrently public void SemaphoreUsage() { bool lLocked = false; try { lLocked = _Semaphore.WaitOne(); DoSomething(); } finally { if (lLocked) _Semaphore.Release(); } } //
public final void DoSomething() { System.out.println("Good night my dear thread " + Thread.currentThread().getId()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } private Object lAnyObject2 = new Object(); public final void LockUsage() { synchronized (lAnyObject2) { DoSomething(); } } // Limits the number of threads that can access a resource or pool of resources concurrently. private static java.util.concurrent.Semaphore _Semaphore = new java.util.concurrent.Semaphore(3); // three objects allowed to access concurrently public final void SemaphoreUsage() { try { _Semaphore.acquire(); DoSomething(); } catch (InterruptedException e) { e.printStackTrace(); } finally { _Semaphore.release(); } }
Mutex
public void DoSomething() { Console.WriteLine("Good night my dear thread " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); } // private const string cMutexName = "MyMutex"; private static Mutex _Mutex = new Mutex(false, cMutexName); // known by every process public void MutexUsage() { bool lLocked = false; try { // optional complexity: access rights //bool lNewCreation; //MutexSecurity lSecurity = new MutexSecurity(); //SecurityIdentifier lId = new SecurityIdentifier(WellKnownSidType.WorldSid, null); //MutexRights lRights = MutexRights.Synchronize | MutexRights.Modify; //lSecurity.AddAccessRule(new MutexAccessRule(lId, lRights, AccessControlType.Allow)); //_Mutex = new Mutex(false, cMutexName, out lNewCreation, lSecurity); //MutexSecurity lReverse = _Mutex.GetAccessControl(); lLocked = _Mutex.WaitOne(2000); // You can the option to set a time limit. Here 2000 milliseconds. if (!lLocked) { Console.WriteLine("Try again later. Mutex is used by another process or thread."); } DoSomething(); } finally { if (lLocked == true) _Mutex.ReleaseMutex(); } } //
// no mutexes available // use the synchronized block
void DoSomething() { cout << "Good night my dear thread " << this_thread::get_id() << endl; this_thread::sleep_for(chrono::milliseconds(2000)); } mutex _Mutex; void MutexUsage(){ _Mutex.lock(); try { DoSomething(); } catch (string e){ _Mutex.unlock(); throw e; } _Mutex.unlock(); } mutex _Mutex2; void MultipleMutexUsage(){ int x = try_lock(_Mutex, _Mutex2); if (x == -1) { DoSomething(); _Mutex.unlock(); _Mutex2.unlock(); } else cout << "failed to obtain lock for " << (x ? "_Mutex" : "_Mutex2") << endl; } void MutexUsage_For_Forgetful_People(){ lock_guard<mutex> guard(mutex); DoSomething(); } // auto unlocks here
operator overloading
public class myClass { // this class is not thread safe int[] Values = { 1, 2, 3 }; public static myClass operator +(myClass a, myClass b) { int n = a.Values.Length; myClass lNewClass = new myClass(); for (int i = 0; i < n; i++) lNewClass.Values[i] = a.Values[i] + b.Values[i]; return lNewClass; } // public static double operator *(myClass a, myClass b) { int n = a.Values.Length; int lSum = 0; for (int i = 0; i < n; i++) lSum += a.Values[i] * b.Values[i]; return lSum; } // public static string operator +(string a, myClass b) { //return ">> " + a + b + "<<"; // WRONG! causes recursion return ">> " + a + b.ToString() + "<<"; } // // I will explanation this in my post on Tuesday 4 February 2014 // uncomment this and play with it (=>hardcore C#) //public static string operator +(myClass a, string b) { // //return ">> " + a + b + "<<"; // WRONG! causes recursion // return ">> " + a + b.ToString() + "<<"; //} // // becomes even more hardcore when you have two conflicting overloads public override string ToString() { return "Values: " + Values[0] + " " + Values[1] + " " + Values[2] + " "; } // } // class public static void test() { myClass a = new myClass(); myClass b = new myClass(); myClass c = a + b; double d = a * b; Console.WriteLine("(Sum) " + c); // ">> (Sum) Values: 2 4 6 <<" Console.WriteLine("(Sum) " + c.ToString()); // "(Sum) Values: 2 4 6" Console.WriteLine(c + " (Sum)"); // "Values: 2 4 6 (Sum)" Console.WriteLine(d); // 14 Console.ReadLine(); } //
// there is no operator overloading available in Java
#include <string> #include <iostream> #include <memory> using namespace std; namespace OperatorOverloading { class myClass { private: int *Values = new int[] { 1, 2, 3 }; public: myClass &operator + (const myClass &b); //const string operator + (const myClass &b); // not possible to distinguish by return type only const string myClass::operator + (int &i); myClass &operator + (const int &i); // this is possible 🙂 double operator *(const myClass &b); const string ToString(); }; // class myClass &myClass::operator + (const myClass &b) { myClass *lNewClass = new myClass(); for (int i = 0; i < 3; i++) lNewClass->Values[i] = Values[i] + b.Values[i]; return *lNewClass; } myClass &myClass::operator + (const int &i) { myClass *lNewClass = new myClass(); for (int i = 0; i < 3; i++) lNewClass->Values[i] = 3 + Values[i]; return *lNewClass; } const string myClass::operator + (int &i) { return ">> " + ToString() + " -- " + to_string(i) + "<<"; } // const string myClass::operator + (const myClass &b) {} not possible double myClass::operator *(const myClass &b) { int lSum = 0; for (int i = 0; i < 3; i++) lSum += (this->Values[i]) * (b.Values[i]); return lSum; } const string myClass::ToString() { string s1 = to_string(Values[0]); string s2 = to_string(Values[1]); string s3 = to_string(Values[2]); return "Values: " + s1 + " " + s2 + " " + s3; } } // namespace int main() { using namespace OperatorOverloading; myClass a, b; myClass c = a + b; cout << c.ToString() << endl; // Values: 2 4 6 double d = a * b; cout << d << endl; // 14 myClass e = a + 3; cout << c.ToString() << endl; // Values: 5 7 9 cin.get(); return 0; }