Click here to Skip to main content
Click here to Skip to main content

How to pass data to worker threads

By , 30 Oct 2001
 

Introduction

There are some things about the .NET threading classes that I have not appreciated much. The first shock I got was when I realized that the System::Threading::Thread class was a sealed class.

public __gc __sealed class Thread

That means we cannot derive from the Thread class. If Thread was not sealed, then things would have been really easy. We derive a class from Thread, say MyThread. Then we add a struct member to MyThread so that we can populate our struct before starting the thread. This would have been a clean way to pass data to our thread.

As if that was not bad enough, my next shock was when I realized that the thread proc delegate would not take any parameters.

public __gc __delegate void ThreadStart();

The API function CreateThread has an LPVOID paramater using which we can pass a struct or class pointer to pass data to our threads. The CRT functions _beginthread and  _beginthreadex have a void* argument which we can use similarly.

Well so how do we get around these drawbacks. I presume that there are some very valid reasons for the Thread class and the ThreadStart delegate having the above mentioned definitions. And if someone knows why they are so, I'd be glad if you can enlighten me.

I might have missed out on something. Two likely candidates are AllocateDataSlot and AllocateNamedDataSlot. I haven't really understood their exact purpose. But I guess I'll have to search deeper into the documentation.

Anyway for now I have found the following solutions. We have our own managed class. And we add a Thread member to our class. And  in our constructor we start our thread using the Thread member. I am not sure whether this is an ideal solution. The following program listing will try and make things clear.

Program Listing

#include "stdafx.h"

#using <mscorlib.dll>

using namespace System;
using namespace System::Threading;

__gc class CalcThread
{
public:
    CalcThread(int num,String *s);
private:
    void ThreadFunc();
    Thread *t;
    int x;
    String *s1;
};

int wmain(void)
{   
    CalcThread *c1,*c2,*c3;
    Console::WriteLine("Starting thread c1");
    c1=new CalcThread(77,"c1");
    Console::WriteLine("Starting thread c2");
    c2=new CalcThread(66,"c2");
    Console::WriteLine("Starting thread c3");
    c3=new CalcThread(99,"c3");
    return 0;
}

CalcThread::CalcThread(int num, String *s)
{
    x=num;
    s1=s;
    t=new Thread(new ThreadStart(this,&CalcThread::ThreadFunc));	
    t->Start();
}

void CalcThread::ThreadFunc()
{
    Console::WriteLine("Thread {0} has initialized",s1);
    for(int i=0;i<5;i++)
    {		
        x^=i;
        Console::WriteLine("Thread {0} Intermediate Result : {1}",
            s1,__box(x));
        Thread::Sleep(500);
    }
    Console::WriteLine("Thread {0} finished with result {1}",
        s1,__box(x));
}

Output

D:\MyProjs\mcppthreads01\Debug>mcppthreads01.exe
Starting thread c1
Starting thread c2
Starting thread c3
Thread c1 has initialized
Thread c1 Intermediate Result : 77
Thread c2 has initialized
Thread c2 Intermediate Result : 66
Thread c3 has initialized
Thread c3 Intermediate Result : 99
Thread c1 Intermediate Result : 76
Thread c2 Intermediate Result : 67
Thread c3 Intermediate Result : 98
Thread c1 Intermediate Result : 78
Thread c2 Intermediate Result : 65
Thread c3 Intermediate Result : 96
Thread c1 Intermediate Result : 77
Thread c2 Intermediate Result : 66
Thread c3 Intermediate Result : 99
Thread c1 Intermediate Result : 73
Thread c2 Intermediate Result : 70
Thread c3 Intermediate Result : 103
Thread c1 finished with result 73
Thread c2 finished with result 70
Thread c3 finished with result 103

D:\MyProjs\mcppthreads01\Debug>

Thank You

License

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

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
AnswerSystem::Threading::Thread class is a sealed classmemberhariseos20 May '12 - 23:27 
There are some things about the .NET threading classes that I have not appreciated much. The first shock I got was when I realized that the System::Threading::Thread class was a sealed class.
 
There is a simple reason for this:
Thread must be thought of as a (Wrapper) class to manage a thread, but not as the actual code or object that runs in that thread. To use Thread to manage a thread, subclassing is hardly ever needed. Instead, create a worker object and implement need functions on that worker to perform the work you need doing.
GeneralThread waitingsussOleshii20 Jan '04 - 0:47 
Hi !
I've some trouble. I'm introduce about next things.
There are some threads, which want waiting for some event.
When this event will become as free, this threads will invoke
some callback. How i can design this thing ?
Beforehand grateful.
QuestionPassing Data?memberWilliam E. Kempf31 Oct '01 - 12:21 
You have two questions in the beginning of your article. The first is why MS chose to not let you inherit from Thread. I can't explain why MS chose this route (though I chose the same design for Boost.Threads so I can speculate), but in general even Java programmers are instructed to prefer implementing the Runnable interface. It's generally a cleaner solution. That said, as others have pointed out your given "solution" in this article could easily be used to create your own ThreadBase class from which you can inherit making your ThreadBase the Thread you wish MS had provided.
 
The second question was why you couldn't pass data to the delegate. This is much easier to answer. Because there's no need to. The delegate concept wraps up both an object "pointer" and an object method into a single "callable" concept. So the delegate, by definition, carries data with it. You illustrated this in your "solution", the only difference is that you encapsulated the thread creation within the object's constructor. Move this creation to user code instead and you've got your solution for "passing data" to the threads you create. As someone else pointed out this is a variation on the Runnable concept from Java with looser coupling, which is always a good thing.
 
The Boost.Threads (http://www.boost.org) library takes a similar approach in a pure C++ style. Threads are created with "function objects" (in case you aren't familiar with this a function object can be either a function pointer or an object instace of a class with an overloaded operator() which can be called with the same syntax as a function pointer) that take no parameters and return void. If you need to pass data to the thread or return a data from the thread when it exits you do so through state (data members) within the function object. This is really a much more flexible and powerful design then the traditional C style designs of POSIX and Win32. Especially with facilities such as Boost.Bind or expression templates.
 
William E. Kempf
AnswerRe: Passing Data?memberNish [BusterBoy]31 Oct '01 - 13:08 
Wow!
 
Thanks William....
 
Nish
GeneralDeriving from Thread classmemberDaniel Turini30 Oct '01 - 23:36 
I did not use .NET yet, so the question may looks dumb, but to me it seems that an obvious way to pass data to the thread is to derive a class from Thread (in fact, creating a private member is a way of implementing a OOP design with inheritance in languages that do not support it)
Why can't you derive a Thread class ?

 
Furor fit laesa saepius patientia
GeneralRe: Deriving from Thread classmemberNish [BusterBoy]30 Oct '01 - 23:50 
Hello Daniel
 
The Thread class in .NET is sealed.
Means you CANNOT derive from the Thread class.
I had specifically mentioned that in the beginning of the article.
 
Nish
GeneralRe: Deriving from Thread classmemberDaniel Turini31 Oct '01 - 0:16 
I had specifically mentioned that in the beginning of the article.
Excuse me, you're right (I think I was still sleeping when I read your article).
But then, a way of keeping things more easy would be creating a generic MyThread class (not sealed, obvously) and derive your thread classes from it.
 
It seems Microsoft still wants to keep us writing proprietary generic Thread wrapper classes...

 
Furor fit laesa saepius patientia
GeneralRe: Deriving from Thread classmemberNish [BusterBoy]31 Oct '01 - 0:40 
Smile | :)
 
Yeah, perhaps!
 
Nish
GeneralRe: Deriving from Thread classmemberJörgen Sigvardsson30 Oct '01 - 23:51 
because it's marked as sealed as this article points out.
 
If you have worked with java before, you can regard microsofts "sealed" as javas "final". (Ever tried to subclass java.lang.String? Smile | :)
 
Strings in java are final because they are both a part of the java class libraries and the language itself. Sun just didn't want the users to be able to "rework" the language itself I guess. Most likely thats the reason behind the sealed Thread class in .NET. (Hmm.. that sure looks a lot like .NOT. in FoxPro.. Wink | ;)
GeneralRe: Deriving from Thread classmemberNish [BusterBoy]31 Oct '01 - 0:42 
Yeah
 
One of my buddies is a Java-guy
He says that all you have to do in Java is to derive from some thing called Runnable in Java
 
Nish
GeneralRe: Deriving from Thread classmemberJörgen Sigvardsson31 Oct '01 - 1:10 
You implement Runnable rather. It's an interface which exposes the void run() method which can be called by a Thread.
 
In java you are given two choices, either to derive from Thread or you implement Runnable. Implementing the Runnable interface is the preferred way for "ordinary" worker threads (at least it was in java 1.{0,1}, I never bothered to look into 1.{2,3} or 2.x).
 
A Runnable interface actually makes a lot of sense. Deriving from a thread for the sake of implementation is not a good design (unless you are using some template pattern, but that doesn't mean i like it.. Wink | ;) ). It seems to me that MS solved it by using a delegate instead of using an interface. This is cleaner than an interface since it requires a weaker coupling to the target working object.
GeneralRe: Deriving from Thread classmemberNish [BusterBoy]31 Oct '01 - 6:24 
Thanks!
 
My java is not exactly strong Smile | :)
 
Nish
GeneralRe: Deriving from Thread classmemberreader31 Oct '01 - 9:05 
What your strong?
GeneralRe: Deriving from Thread classmemberNish [BusterBoy]31 Oct '01 - 13:08 
Smile | :)
 
I like the sarcasm Smile | :)
 
Nish
GeneralThis time...memberNish [BusterBoy]30 Oct '01 - 20:49 
Chris
 
This time I refrained from using any <code> tags
 
Smile | :)
 
Nish
GeneralAllocateStoragesussAnonymous24 May '04 - 10:30 
It is used for internal purposes. No external thread can touch the data inside of it. Only the current executing thread. Kinda useless unless your opening a file storing the data in the thread then calling another function without parameters then pulling the data out of the local storage.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 31 Oct 2001
Article Copyright 2001 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid