STL & multithreading

A

Axter

Ioannis said:
Axter said:
#using <mscorlib.dll>

#include <vector>
#include <iostream>


__gc class SomeClass
{
std::vector<int> *pvec;

public:
SomeClass()
{
pvec= new std::vector<int>(1000);
}

~SomeClass()
{
delete pvec;
}

void Write1()
{
for(std::vector<int>::size_type i=0; i<200; ++i)
(*pvec)= i;
}

void Write2()
{
for(std::vector<int>::size_type i=200; i<400; ++i)
(*pvec)= i;
}

void Write3()
{
for(std::vector<int>::size_type i=400; i<600; ++i)
(*pvec)= i;
}

void Write4()
{
for(std::vector<int>::size_type i=600; i<800; ++i)
(*pvec)= i;
}

void Write5()
{
for(std::vector<int>::size_type i=800; i<1000; ++i)
(*pvec)= i;
}

void DisplayValues()
{
using namespace std;

for(vector<int>::iterator p= pvec->begin(); p!=


pvec->end(); ++p)
cout<<*p<<"\t";
}
};


int main()
{
using namespace System;
using namespace System::Threading;
using namespace std;


SomeClass *pSomeClass= __gc new SomeClass;

Thread *pthread1= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write1) );
Thread *pthread2= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write2) );
Thread *pthread3= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write3) );
Thread *pthread4= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write4) );
Thread *pthread5= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write5) );


pthread1->Start();
pthread2->Start();
pthread3->Start();
pthread4->Start();
pthread5->Start();


// Main thread waits for some time to let the other threads
finish

Thread::Sleep(5000);

pSomeClass->DisplayValues();
}

Of course no thread locking is required for this type of code, because
your threads are not access the same data.
Each thread has it's own block of data.
Thread synchronization is needed when you're access and modifying the
same chunck of data.
This is not an example of such a requirement, and there for no need for
a ThreadSafeObject wrapper class, nor is there a need for application
level lock.




Exactly. Still the vector along with the rest standard library in the specific compiler is
"thread-safe" in the sense that it allows multithreading operations

on it.

I never claim that compilers do not have thread safe classes. Did you
not read my detailed explanation on the difference between a thread
safe class and a thread safe object?
If the vector wasn't "thread-safe", then the above assignments would
not be well defined.

That's right, and this has nothing to do with needing a thread safe
object. This is only relevant to thread safe class.
In the case of accessing the same data, of course thread-locking is needed, but this is in
the application's logic.
Wrapping the entire vector however, and acquiring the lock at each different element
access would be inefficient, wouldn't it?

In the example code you posted, it would be inefficient and completely
unnecessary to lock the entire vector.
However, if you need to modify the vector itself, to include increasing
and decreasing the size of the vector, then wrapping the entire vector
would be the more efficient and the safer approach. It would be more
inefficient to apply an entire application level lock just for the
locking requirements of one object.
If you put your OOP hat on, this would be easier to understand.
The class wrapper method is not only more object orientated, but its
safer, it's easier to maintain, and can be more efficient.
 
A

Axter

Ioannis said:
Axter said:
#using <mscorlib.dll>

#include <vector>
#include <iostream>


__gc class SomeClass
{
std::vector<int> *pvec;

public:
SomeClass()
{
pvec= new std::vector<int>(1000);
}

~SomeClass()
{
delete pvec;
}

void Write1()
{
for(std::vector<int>::size_type i=0; i<200; ++i)
(*pvec)= i;
}

void Write2()
{
for(std::vector<int>::size_type i=200; i<400; ++i)
(*pvec)= i;
}

void Write3()
{
for(std::vector<int>::size_type i=400; i<600; ++i)
(*pvec)= i;
}

void Write4()
{
for(std::vector<int>::size_type i=600; i<800; ++i)
(*pvec)= i;
}

void Write5()
{
for(std::vector<int>::size_type i=800; i<1000; ++i)
(*pvec)= i;
}

void DisplayValues()
{
using namespace std;

for(vector<int>::iterator p= pvec->begin(); p!=


pvec->end(); ++p)
cout<<*p<<"\t";
}
};


int main()
{
using namespace System;
using namespace System::Threading;
using namespace std;


SomeClass *pSomeClass= __gc new SomeClass;

Thread *pthread1= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write1) );
Thread *pthread2= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write2) );
Thread *pthread3= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write3) );
Thread *pthread4= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write4) );
Thread *pthread5= __gc new Thread (__gc new
ThreadStart(pSomeClass,

&SomeClass::Write5) );


pthread1->Start();
pthread2->Start();
pthread3->Start();
pthread4->Start();
pthread5->Start();


// Main thread waits for some time to let the other threads
finish

Thread::Sleep(5000);

pSomeClass->DisplayValues();
}

Of course no thread locking is required for this type of code, because
your threads are not access the same data.
Each thread has it's own block of data.
Thread synchronization is needed when you're access and modifying the
same chunck of data.
This is not an example of such a requirement, and there for no need for
a ThreadSafeObject wrapper class, nor is there a need for application
level lock.




Exactly. Still the vector along with the rest standard library in the specific compiler is
"thread-safe" in the sense that it allows multithreading operations on it.

If the vector wasn't "thread-safe", then the above assignments would not be well defined.


In the case of accessing the same data, of course thread-locking is needed, but this is in
the application's logic.


Wrapping the entire vector however, and acquiring the lock at each different element
access would be inefficient, wouldn't it?



I forgot to mention, that if you have manage code, like the code you
posted, you don't need the ThreadSafeObject class I posted.
..Net has a Monitor class that can do this object base locking for you.
The syntax is something like the following:
Monitor::Enter(pvec);
//do something with pvec here
Monitor::Exit(pvec);

If object level locking is not needed for your compiler, do you think
MS would have wasted time creating this Monitor class?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,771
Messages
2,569,587
Members
45,097
Latest member
RayE496148
Top