CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 13 of 13
  1. #1
    Join Date
    Jan 2003
    Posts
    375

    Can local variable be passed as parameter into a new thread?

    Can local variable be passed as the parameter for a new created thread procedure? Here is the example code:

    Code:
    void CDLG::some_function()
    {
    	CString strFileName="abc.doc"; 
    	//local variable, can it be valid for being passed into the following new thread???	
            //Can strFileName still be accessed from within the stack of thread procedure? 
    	::AfxBeginThread(ProcessContentThread,(LPVOID)&strFileName);
    }
    
    UINT ProcessContentThread(LPVOID p) 
    {
    	CString* pstr=(CString*)p
    	CString strFile=*pstr;
    	//process the file
    	...
    
    }
    There is another method using variable on the heap,

    Code:
    void CDLG::some_function()
    {
    	CString strFileName="abc.doc";  
    	CString* pstrFN=new CString(strFileName); 	
    	::AfxBeginThread(ProcessContentThread,(LPVOID)pstrFN);
    }
    
    UINT ProcessContentThread(LPVOID p) 
    {
    	CString* pstr=(CString*)p
    	CString strFile=*pstr;
    	delete pstr;
    	//process the file
    	...
    
    }
    I test these code, both methods work as expected, but I doubt whether the first method is a good way. OR if only the second method is the correct way to pass a parameter to a thread. Thank you for help!
    Last edited by forester; April 1st, 2013 at 04:20 AM.

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by forester View Post
    I test these code, both methods work as expected,
    C++ doesn't work that way. Just because a test "works" doesn't mean that the code isn't faulty. This is especially the case when you're using threads -- you cannot just assume that code that uses threads work because it works on your machine, as that is the absolute worst way to write and test a program that uses threads. This is where you need static code analysis, i.e. know that the code is faulty without needing to run anything.

    The first code is obviously wrong. The simple reason is that the variable will be destroyed at the end of the block it is declared in -- those are the rules of C++. Given your code, you cannot guarantee that the CString declared locally will even exist by the time the thread begins to execute.

    All you're doing when you call AfxBeginThread() is that you're making a function call. That's it, nothing else -- it doesn't matter what that function does -- just because it does something special, i.e. starts a thread, means nothing. After AfxBeginThread() returns, then the code proceeds from there, hitting the end of the function, thus destroying the CString variable. That is how you should be looking at the code, and that is from a C++ standpoint and not a threading standpoint.

    Since you want that CString to stay alive, then the way to do it is to dynamically allocate it, thereby you're controlling its lifetime. Since you know when you need to destroy the CString, then the second code is safer.

    Also, a local variable can be passed if it is one where you're making a copy of that local variable and passing it to the routine. Obviously, you're not doing that.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; April 1st, 2013 at 06:09 AM.

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Can local variable be passed as parameter into a new thread?

    Another approach is to make the string a member variable of the dialog. Keep in mind that you'll need to synchronize access to the string if the string gets modified while the worker thread is using the string. In other words, passing a read-only string to a worker thread is okay.

  4. #4
    Join Date
    Jan 2003
    Posts
    375

    Re: Can local variable be passed as parameter into a new thread?

    Thank you for your replies!

    Also, a local variable can be passed if it is one where you're making a copy of that local variable and passing it to the routine. Obviously, you're not doing that.
    I don't know how to implement it. If I make a copy of that local variable, and that copy is a local variable too, then the copy is still not safe to be accessed from within the new created thread procedure, i.e. ProcessContentThread(LPVOID p), Could you give me example code? Thank you!
    Last edited by forester; April 1st, 2013 at 09:34 PM.

  5. #5
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by forester View Post
    If I make a copy of that local variable,
    Again, look at this from a C++ perspective.

    Passing by value makes a copy of the item being passed.
    Code:
    void foo(int x)
    {
    }
    
    int main()
    {
       int z = 10;
       foo(z);
    }
    A temporary copy of z is made when foo is called. That temporary copy lasts the lifetime of foo().

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; April 1st, 2013 at 11:44 PM.

  6. #6
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,395

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by forester View Post
    Can local variable be passed as the parameter for a new created thread procedure?
    Have a look at this essay: Using Worker Threads
    Victor Nijegorodov

  7. #7
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by forester View Post
    Can local variable be passed as the parameter for a new created thread procedure?
    This is easy with modern C++.
    (Edit: code is incorrect, see post # 12)
    Code:
    #include <thread>
    
    void CDLG::some_function()
    {
    	CString strFileName="abc.doc";
    	std::thread(std::bind(ProcessContentThreadFunction, strFileName));
    }
    
    void ProcessContentThreadFunction(CString fileName)
    {
    	// process the file
    }
    If your compiler doesn't support std::thread, you can use boost::thread instead.
    Last edited by D_Drmmr; April 4th, 2013 at 03:21 AM. Reason: added note
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  8. #8
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Can local variable be passed as parameter into a new thread?

    D Drmmr, don't you still have the scoping issue?

  9. #9
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by Arjay View Post
    D Drmmr, don't you still have the scoping issue?
    The CString is passed by value, so there shouldn't be a problem on the surface.

    However, I don't have the source code to CString at the moment, so I'll ask:

    If CString is reference counted, is the reference counting thread-safe? In other words, if that temporary copy used in ProcessContentThreadFunction() is destroyed simultaneously with the destruction of the CString in some_function, is this guaranteed to be OK?

    Regards,

    Paul McKenzie

  10. #10
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by Arjay View Post
    D Drmmr, don't you still have the scoping issue?
    No, the CString is passed by value. std::bind will create a std::function<void()> object that (internally) stores a copy of the string. When this object is called by std::thread, the copied string is passed to the 'ProcessContentThreadFunction' function.

    In fact, std::bind by default creates a copy of the arguments passed. If you want to pass by reference, you need to wrap the argument in std::ref.
    Code:
    #include <functional> // bind
    #include <iostream>
    
    void foo(int& i)
    {
       std::cout << &i << std::endl;
    }
    
    int main()
    {
       int i;
       foo(i);
       std::bind(foo, i)();
       std::bind(foo, std::ref(i))();
    }
    Output from http://liveworkspace.org/
    Code:
    stdout: 
    0x7fffdbcd31ac
    0x7fffdbcd31b8
    0x7fffdbcd31ac
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  11. #11
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by Paul McKenzie View Post
    However, I don't have the source code to CString at the moment, so I'll ask:

    If CString is reference counted, is the reference counting thread-safe? In other words, if that temporary copy used in ProcessContentThreadFunction() is destroyed simultaneously with the destruction of the CString in some_function, is this guaranteed to be OK?
    That's a good question. In the implementation of CString on VS2005 and VS2008, I see that the reference count is in-/decremented with interlocked* functions. I think that's enough to make the CoW implementation thread-safe. I.e. if no single CString object is accessed from multiple threads unsynchronized, I don't see how it can fail.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  12. #12
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Can local variable be passed as parameter into a new thread?

    D Drmmr, that code doesn't seem correct to me because std::thread destructor will call terminate() if still joinable ( due to exception safety reasons ). Hence, you must either detach() or join() in some_function().

    note that boost::thread had a different behavior as it automatically detached itself during destruction. Newest versions conforms to the std behavior though ( don't recall the exact version ... ).

    BTW, one can use a lambda with by-value capture in place of std::bind ( more readable IMHO, and you can gain one less allocation and no virtual call ) or even just write "std::thread( ProcessContentThreadFunction, strFileName );" ( everything is copyed in the calling thread and the thread ctor syncs with the ProcessContentThreadFunction call; that said, I cannot recall from which VC++ version this is actually supported ... ) or use std::async ( but you need to take care of the future<> in this case, otherwise the caller will block as in std::thread(...).join() ).

  13. #13
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Can local variable be passed as parameter into a new thread?

    Quote Originally Posted by superbonzo View Post
    D Drmmr, that code doesn't seem correct to me because std::thread destructor will call terminate() if still joinable ( due to exception safety reasons ). Hence, you must either detach() or join() in some_function().

    note that boost::thread had a different behavior as it automatically detached itself during destruction. Newest versions conforms to the std behavior though ( don't recall the exact version ... ).
    Thanks, I've only used boost::thread before and assumed its behavior was the same as std::thread. Good to know this.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured