Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++
Hello Forum Members
 
I come here with a question regarding multithreading in MS VC++ 2010. I have written a class for Monte Carlo calculations. In this class a bond portfolio is evaluated over a time horizon of 10 years subject to 10,000 paths of interest rate terms structures, each one defined by at least 20 points on the curve. As the calculation takes some time I was tempted to have a look at multithreading. This did not proceed as smoothly as initially I had expected while applying most of what is written in the chapter “Creating Threads (Windows) of the msdn web sites.
 
The class looks schematically like this:
Class MC_Simulation{
	SCENARIO 	Scenarios[10,000];
		
	PORTFOLIO	Bond_Portfolio;
public:
	MC_Simulaion(void);
	~MC_Simulation(void);
	void read_scenario_data_file(const char* file);
	void read_portfolio_data_file(const char* file);
	void initiate_threads(void);
	static DWORD WINAPI bond_portfolio_thread_function(LPVOID arg);
 
}  // end class
The essential problem is that “bond_portfolio_thread_function” must be declared static and can no longer access the information of classes Scenarios[] and Bond_Portfolio. How can I proceed from here?
 
The facts are that scenario data do not change in the course of the simulation. The thread function is supposed to use the (fixed) scenario data for the evaluation of the bonds in Bond_Portfolio. The content of Class Bond_Portfolio is changed for each scenario. LPVOID arg determines the partition of Scenarios to be considered per thread. LPVOID arg could also take a copy of Bond_Portfolio, in which case the calculation per thread would be entirely independent of each other. How can I build a thread function which can use the information in the private part of the class? If not possible, which is the way around the problem?
Posted 11-Oct-12 13:30pm
Edited 12-Oct-12 4:35am
v3
Comments
Sergey Alexandrovich Kryukov at 11-Oct-12 19:58pm
   
Right question! My 5.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

You can make a small wrapper to the thread, for easy threading:
Can't we use threads inside the member function of class?[^]
  Permalink  
Comments
Sergey Alexandrovich Kryukov at 12-Oct-12 12:39pm
   
Exactly, my 5. This is pretty much what I advised.
(Hm. Someone down-voted both answers. I already faced with flame wars around this approach to threading, when the "opponents" fought it bases on "religious" arguments... it could be similar motivation, I don't know.)
--SA
armagedescu at 15-Oct-12 7:25am
   
Than you, I've given also a vote
Sergey Alexandrovich Kryukov at 15-Oct-12 11:19am
   
Thank you.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

A thread function should be static. Therefore we cannot access the non-static members from the thread function.
 
We can solve this issue by passing address of class instance to the thread function. In thread function, we will convert it to an instance of class object and can call member functions of the class.
 
class MyClass
{
   struct THREAD_INFO
   {
      MyClass* pInstance;
      int      nScenarioToStart; // Information to a thread.
      .... // Add additional information for a thread.
   }
   UINT ThreadFunc( LPVOID pInstance )
   {
        THREAD_INFO* pThreadInfo = (THREAD_INFO*)pInstance;
        pThreadInfo->pInstance->ThreadImpl(pThreadInfo); // Calling member function from thread.
        return 1;
   )
 
   void ThreadImpl(THREAD_INFO* pThreadParam)
   {
     // pThreadParam holds parameters for each threads.
     // Actual thread implementation.
     // It is important to synchronize the access to class members by different threads.
   }
}
  Permalink  
v2
Comments
nv3 at 12-Oct-12 14:58pm
   
Well done. That leaves some work for allocating and freeing the THREAD_INFO structures and I hope the questioner will figure out how to do that correctly without producing a memory leak. +5
Sergey Alexandrovich Kryukov at 12-Oct-12 15:18pm
   
Agree. Voting 5, too.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

I would suggest the following method:
 
Wrap the thread in the class (let's call it ThreadWrapper, and in some instance (non-static) function used to create a thread, pass "this" as a parameter LPVOID arg of the static function bond_portfolio_thread_function. In this function, you will need to cast LPVOID to ThreadWrapper *. This way, you will get access to all members of this wrapper class from the implementation of the thread body. In a way, you will imitate the mechanism of getting access to the instance members by instance functions, by explicit passing of the access-to-the-instance parameter, which is passed implicitly as a hidden parameter of instance function. This way, you make this static function behaving like an instance one.
 
(Why this method is not used in OS APIs which would allow using instance functions as the thread start functions? Only because those OS are based on legacy code, which is "not object-oriented enough" and OS API can be uses by C and other non-OOP languages. In true object-oriented platforms (example: .NET, CLI), a thread start method can be non-static.)

 
However, you should be careful not to provide direct access to the instance members of this instance of ThreadWrapper. As those members becomes a matter of shared access, so you need to provide access not directly, but via some functions wrapping access to the members using appropriate thread synchronization primitives (critical section, mutex…). This is yet another benefit of the thread wrapper based approach: you can totally hide those synchronization primitives from the code using of the class, yes making access thread safe.
 
—SA
  Permalink  
Comments
nv3 at 12-Oct-12 15:05pm
   
Definitely the way to go. I like the fact that you pointed out that ThreadWrapper is not only good to forward the static function call into a non-static member, but can also be used to handle the synchonization issues.
 
Whoever has voted this answer down should have the courage to explain, why he didn't like that solution. If it was the questioner, then don't hesitate to ask for some sample code that explains what Sergey is talking about.
Sergey Alexandrovich Kryukov at 12-Oct-12 15:17pm
   
Thank you very much.
Pleasure to talk with a person who understand such things, unlike some others.
There are other good answers here.
Unfortunately, some apparently ignorant member voted 1 for everything, including the question, which I up-voted. I explained my guess on the motivation in my comment to Solution 3, but it would not explain down-voting of the question. Probably, usual vandalism, which apparently happens time to time.
--SA
haraldhubbes at 13-Oct-12 8:44am
   
Hello Forum Members
 
As the person having asked the question I have to thank you for all the answers.
I would particularly like to thank Mr Sergey Alexandrovich for his comments. In the first place I am glad that my question apparently has not been too displaced. Now I need to digest all the suggestions.
 
For now, I must understand that actually my class MC_Simulation will not be made a "copy" of for each thread. This would not work in a 32bit environment. With my huge amount of scenario data I approach 4gb memory.
 
To be more precise, in the msdn article, which I mentioned in my question, rightly allocates memory to the parameter ("pDataArray"), which is sent to the threadfunction as LPVOID arg. The memory which is consumed by the pointer to the threadfunction must not be too much.... (at least for the time being until I have progressed to 64b compiling).
 
I am not so familiar with the voting rules of code project. My impression is that all solutions are somehow similar. For now I will go for solution two, which gives a code example. Can the administrator advise me, whether I can grade all solutions highly or only one of them?
Harald Hubbes
Sergey Alexandrovich Kryukov at 14-Oct-12 1:45am
   
You are very welcome.
 
I would ask you to accept the solution(s) formally (green button).
Which solutions? Those you think make sense.
 
You can always accept more then one, and I recommend you to do so. Please see my comments to other solutions. So, I would recommend you to accept Solution 1, 2 and 3 (all that posted at the moment of writing).
 
For your understanding: voting and accepting are different things. Accepting is only available to the original post author (the person who asked the question). Accepting is encouraged if a solution deserves it, so the solution would have some status. However, accepting one or more answers does not block the question from getting more answers; it just mark the question as answered. Often, the question marked as answered keep getting more and more feedback, if some members find it interesting.
 
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 12 Oct 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100