Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
4.00/5 (4 votes)
See more:
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:
C++
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
Updated 12-Oct-12 4:35am
v3
Comments
Sergey Alexandrovich Kryukov 11-Oct-12 19:58pm    
Right question! My 5.
--SA

You can make a small wrapper to the thread, for easy threading:
Can't we use threads inside the member function of class?[^]
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 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 15-Oct-12 7:25am    
Than you, I've given also a vote
Sergey Alexandrovich Kryukov 15-Oct-12 11:19am    
Thank you.
--SA
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.

C++
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.
   }
}
 
Share this answer
 
v2
Comments
nv3 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 12-Oct-12 15:18pm    
Agree. Voting 5, too.
--SA
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
 
Share this answer
 
Comments
nv3 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 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 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 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)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900