OLE macro in a for loop - c++

According to MSDN documentation for OLE conversion macros, if we use a macro in a for loop for example, it may end up allocating more memory on stack leading to stack overflow.
This is the example provided on MSDN
void BadIterateCode(LPCTSTR* lpszArray)
{
USES_CONVERSION;
for (int ii = 0; ii < 10000; ii++)
pI->SomeMethod(ii, T2COLE(lpszArray[ii]));
}
In the above example T2COLE is used inside a for loop which may lead to stack overflow, to avoid this the method call is encapsulated into a function like this
void CallSomeMethod(int ii, LPCTSTR lpsz)
{
USES_CONVERSION;
pI->SomeMethod(ii, T2COLE(lpsz));
}
void MuchBetterIterateCode2(LPCTSTR* lpszArray)
{
for (int ii = 0; ii < 10000; ii++)
CallSomeMethod(ii, lpszArray[ii]);
}
Can we just send the LPCTSTR to another function instead of encapsulating the whole method like this,
LPCOLESTR CallSomeMethod(LPCTSTR lpsz)
{
USES_CONVERSION;
return T2COLE(lpsz);
}
void BadIterateCode(LPCTSTR* lpszArray)
{
for (int ii = 0; ii < 10000; ii++)
pI->SomeMethod(ii, CallSomeMethod(lpszArray[ii]));
}
Can anyone tell me if it is safe use of OLE macro or still we may run into stack overflow?
Will there be any other issues by using the above method?

The third example will not work because the T2COLE object created in the method will be destroyed as soon as you return from the function. As you note in your question, the object is created on the stack, and the usual stack rules apply in this situation - the object will be destroyed as soon as you go out of scope, and you'll be accessing garbage data in the 3rd case.
The second case is the correct mechanism to use for using the data without triggering a stack overflow as upon return from the function, the memory that was allocated by the T2COLE will be freed.
I'm not aware of how the implementation of T2COLE works, but in C, you could achieve the same behaviour by using the alloca function which suffers from the same issue - as soon as you return from the function, you should consider the pointer and the data that it points at as invalid.

Related

Shared pointer (this)

I have got an exception throw :0x74AC4192 in main.exe: Microsoft C++ exception: std::bad_weak_ptr at memory location 0x001AF0D0.
in
Gasstation::Gasstation(int n,int m)
{
for (int i = 0; i < n; ++i)
{
pumps_.push_back(std::make_shared<Pumplace>());
}
cashregisters_ = std::make_shared<Cashregister> (shared_from_this(), m);
}
I also used this in the header :
class Gasstation : public std::enable_shared_from_this<Gasstation>
What could be the problem?
The issue with your code here, is that you are calling shared_from_this() within the constructor of the class itself, where strictly speaking, it has not been "made shared" yet. The constructor is called before a smart pointer to the object exists. To follow your example, if creating a shared_ptr to Gasstation:
std::shared_ptr<Gasstation> gasStation = std::make_shared<Gasstation>(5,10);
//gasStation is available as a smart pointer, only from this point forward
Its a limitation of enable_shared_from_this that shared_from_this cannot be called in a constructor.
One solution, though not as elegant, is to have a public method that sets the cashregisters_ variable. The method can be called after construction:
Gasstation::Gasstation(int n, int m)
{
for (int i = 0; i < n; ++i)
{
pumps_.push_back(std::make_shared<Pumplace>());
}
cashregisters_ = std::make_shared<Cashregsiter>(m);
}
Gasstation::initialise_cashregisters()
{
cashregisters_->set_gasstation(shared_from_this());
}
//driver code
std::shared_ptr<Gasstation> gasStation = std::make_shared<Gasstation>(5, 10);
gasStation->initialise_cashregisters();
This solution will require you to remember to call initialise_cashregisters every time you initialise Gasstation.
Short of that, your options are limited, and you may have to rethink your design. Have you considered using raw pointers-to-Gasstation in Cashregister instead of smart pointers? If cashregister_ is a private variable and will never exist beyond the lifetime of the Gasstation it is assigned to, using raw pointers may be a safe and elegant alternative.

Transitioning from C `goto` error handling paradigm to C++ exception handling paradigm

I'm a C programmer learning C++. In C, there is a common goto idiom used to handle errors and exit cleanly from a function. I've read that exception handling via try-catch blocks is preferred in object-oriented programs, but I'm having trouble implementing this paradigm in C++.
Take for example the following function in C which uses the goto error handling paradigm:
unsigned foobar(void){
FILE *fp = fopen("blah.txt", "r");
if(!fp){
goto exit_fopen;
}
/* the blackbox function performs various
* operations on, and otherwise modifies,
* the state of external data structures */
if(blackbox()){
goto exit_blackbox;
}
const size_t NUM_DATUM = 42;
unsigned long *data = malloc(NUM_DATUM*sizeof(*data));
if(!data){
goto exit_data;
}
for(size_t i = 0; i < NUM_DATUM; i++){
char buffer[256] = "";
if(!fgets(buffer, sizeof(buffer), fp)){
goto exit_read;
}
data[i] = strtoul(buffer, NULL, 0);
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
printf("%lu\n", data[i] + data[i + NUM_DATUM/2]);
}
free(data)
/* the undo_blackbox function reverts the
* changes made by the blackbox function */
undo_blackbox();
fclose(fp);
return 0;
exit_read:
free(data);
exit_data:
undo_blackbox();
exit_blackbox:
fclose(fp);
exit_fopen:
return 1;
}
I tried to recreate the function in C++ using the exception handling paradigm as such:
unsigned foobar(){
ifstream fp ("blah.txt");
if(!fp.is_open()){
return 1;
}
try{
// the blackbox function performs various
// operations on, and otherwise modifies,
// the state of external data structures
blackbox();
}catch(...){
fp.close();
return 1;
}
const size_t NUM_DATUM = 42;
unsigned long *data;
try{
data = new unsigned long [NUM_DATUM];
}catch(...){
// the undo_blackbox function reverts the
// changes made by the blackbox function
undo_blackbox();
fp.close();
return 1;
}
for(size_t i = 0; i < NUM_DATUM; i++){
string buffer;
if(!getline(fp, buffer)){
delete[] data;
undo_blackbox();
fp.close();
return 1;
}
stringstream(buffer) >> data[i];
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
cout << data[i] + data[i + NUM_DATUM/2] << endl;
}
delete[] data;
undo_blackbox();
fp.close();
return 0;
}
I feel my C++ version didn't properly implement the exception handling paradigm; in fact, the C++ version seems even less readable and more error prone due to a build of cleanup code accumulating in the catch blocks as the function grows.
I've read that all this cleanup code in the catch blocks may be unnecessary in C++ due to something called RAII, but I'm unfamiliar with the concept. Is my implementation proper, or is there a better way to handle errors and cleanly exit a function in C++?
The principle of RAII is that you use a class type to manage any resource which needs cleaning up after use; that cleanup is done by the destructor.
That means you can create a local RAII manager, which will automatically clean up whatever it's managing when it goes out of scope, whether that's due to normal program flow or an exception. There should never be any need for a catch block just to clean up; only when you need to handle or report the exception.
In your case, you have three resources:
The file fp. ifstream is already an RAII type, so just remove the redundant calls to fp.close() and all is good.
The allocated memory data. Use a local array if it's a small fixed size (as this is), or std::vector if it needs to be dynamically allocated; then get rid of the delete.
The state set up by blackbox.
You can write your own RAII wrapper for the "black box" malarkey:
struct blackbox_guard {
// Set up the state on construction
blackbox_guard() {blackbox();}
// Restore the state on destruction
~blackbox_guard() {undo_blackbox();}
// Prevent copying per the Rule of Three
blackbox_guard(blackbox_guard const &) = delete;
void operator=(blackbox_guard) = delete;
};
Now you can remove all your error-handling code; I'd indicate failure through exceptions (either thrown, or allowed to propagate) rather than a magic return value, giving:
void foobar(){
ifstream fp ("blah.txt"); // No need to check now, the first read will fail if not open
blackbox_guard bb;
const size_t NUM_DATUM = 42;
unsigned long data[NUM_DATUM]; // or vector<unsigned long> data(NUM_DATUM);
for(size_t i = 0; i < NUM_DATUM; i++){
string buffer;
// You could avoid this check by setting the file to throw on error
// fp.exceptions(ios::badbit); or something like that before the loop
if(!getline(fp, buffer)){
throw std::runtime_error("Failed to read"); // or whatever
}
stringstream(buffer) >> data[i]; // or data[i] = stoul(buffer);
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
cout << data[i] + data[i + NUM_DATUM/2] << endl;
}
}
Yes, you should use RAII (Resource Acquisition Is Initialisation) wherever possible. It leads to code which is both easy to read and safe.
The core idea is that you acquire resources during the initialisation of an object, and set up the object so that it correctly releases the resources on its destruction. The vital point why this works is that destructors run normally when scope is exited via an exception.
In your case, there is already RAII available and you're just not using it. std::ifstream (I assume that's what your ifstream refers to) indeed closes on destruction. So all the close() calls in catch can safely be omitted and will happen automatically—precisely what RAII is for.
For data, you should be using an RAII wrapper too. There are two available: std::unique_ptr<unsigned long[]>, and std::vector<unsigned long>. Both take care of memory deallocation in their respective destructors.
Finally, for blackbox(), you can create a trivial RAII wrapper yourself:
struct BlackBoxer
{
BlackBoxer()
{
blackbox();
}
~BlackBoxer()
{
undo_blackbox();
}
};
When rewritten with these, your code would become much simpler:
unsigned foobar() {
ifstream fp ("blah.txt");
if(!fp.is_open()){
return 1;
}
try {
BlackBoxer b;
const size_t NUM_DATUM = 42;
std::vector<unsigned long> data(NUM_DATUM);
for(size_t i = 0; i < NUM_DATUM; i++){
string buffer;
if(!getline(fp, buffer)){
return 1;
}
stringstream(buffer) >> data[i];
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
cout << data[i] + data[i + NUM_DATUM/2] << endl;
}
return 0;
} catch (...) {
return 1;
}
}
Additionally, notice that your function uses a return value to indicate success or failure. This may be what you want (if failure is "normal" for this function), or might just represent only going half-way (if failure is supposed to be exceptional too).
If it's the latter, simply change the function to void, get rid of the try–catch construct, and throw a suitable exception instead of return 1;.
Finally, even if you decide to keep the return value approach (which is perfectly valid), consider changing the function to return bool, with true meaning success. It's more idiomatic.
In C, there is a common goto idiom used to handle errors and exit
cleaning from a function. I've read that exception handling via
try-catch blocks is preferred in object-oriented programs,
That's not true at all for C++.
But C++ has deterministic destructors instead of finally blocks (which are used, for example, in Java), and that's a game changer for error-handling code.
I've read that all this cleanup code in the catch blocks may be
unnecessary in C++ due to something called RAII,
Yes, in C++ you use "RAII". Which is a poor name for a great concept. The name is poor because it puts the emphasis on initialisation (Resource Acquisition Is Initialisation). The important thing about RAII, in contrast, lies in destruction. As the destructor of a local object will be executed at the end of a block, no matter what happens, be it early returns or even exceptions, it's the perfect place for code that releases resources.
but I'm unfamiliar with the concept.
Well, for the very beginning, you can start with Wikipedia's definition:
http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
Or you go straight to Bjarne Stroustrup's website:
http://www.stroustrup.com/bs_faq2.html#finally
I'm sure we'd be more than happy to answer questions about particular aspects of the idiom or problems that you encounter using it :)
Is my implementation proper, or is there a better way to handle
errors and cleanly exit a function in C++?
Your implementation is not what one would expect from good C++ code.
Here is an example using RAII. It uses exceptions to report errors, and destructors to perform cleanup operations.
#include <fstream>
#include <stdexcept>
#include <vector>
// C or low-level functions to be wrapped:
int blackbox();
void undo_blackbox();
// just to be able to compile this example:
FILE *fp;
// The only self-made RAII class we need for this example
struct Blackbox {
Blackbox() {
if (!blackbox()) {
throw std::runtime_error("blackbox failed");
}
}
// Destructor performs cleanup:
~Blackbox() {
undo_blackbox();
}
};
void foobar(void){
// std::ifstream is an implementation of the RAII idiom,
// because its destructor closes the file:
std::ifstream is("blah.txt");
if (!is) {
throw std::runtime_error("could not open blah.txt");
}
Blackbox local_blackbox;
// std::vector itself is an implementation of the RAII idiom,
// because its destructor frees any allocated data:
std::vector<unsigned long> data(42);
for(size_t i = 0; i < data.size(); i++){
char buffer[256] = "";
if(!fgets(buffer, sizeof(buffer), fp)){
throw std::runtime_error("fgets error");
}
data[i] = strtoul(buffer, NULL, 0);
}
for(size_t i = 0; i < (data.size()/2); i++){
printf("%lu\n", data[i] + data[i + (data.size()/2)]);
}
// nothing to do here - the destructors do all the work!
}
By the way, +1 for trying to learn a new concept in a new language. It's not easy to change your mindset in a different language! :)
Let me rewrite that for you using c++ idiom with explanations inline to the code
// void return type, we may no guarantees about exceptions
// this function may throw
void foobar(){
// the blackbox function performs various
// operations on, and otherwise modifies,
// the state of external data structures
blackbox();
// scope exit will cleanup blackbox no matter what happens
// a scope exit like this one should always be used
// immediately after the resource that it is guarding is
// taken.
// but if you find yourself using this in multiple places
// wrapping blackbox in a dedicated wrapper is a good idea
BOOST_SCOPE_EXIT[]{
undo_blackbox();
}BOOST_SCOPE_EXIT_END
const size_t NUM_DATUM = 42;
// using a vector the data will always be freed
std::vector<unsigned long> data;
// prevent multiple allocations by reserving what we expect to use
data.reserve(NUM_DATUM);
unsigned long d;
size_t count = 0;
// never declare things before you're just about to use them
// doing so means paying no cost for construction and
// destruction if something above fails
ifstream fp ("blah.txt");
// no need for a stringstream we can check to see if the
// file open succeeded and if the operation succeeded
// by just getting the truthy answer from the input operation
while(fp >> d && count < NUM_DATUM)
{
// places the item at the back of the vector directly
// this may also expand the vector but we have already
// reserved the space so that shouldn't happen
data.emplace_back(d);
++count;
}
for(size_t i = 0; i < NUM_DATUM/2; i++){
cout << data[i] + data[i + NUM_DATUM/2] << endl;
}
}
The most powerful feature of c++ is not classes, it is the destructor. The destructor allows for resources or responsibilities to be discharged or released when the scope is exited. This means you don't have to re-write cleanup code multiple times. Moreover because only constructed objects can be destructed; if you never get to an item and thus never construct it, you do not pay any penalty in destruction if something happens.
If you find yourself repeating cleanup code, that should be a flag that the code in question is not taking advantages of the power of the destructor and RAII.

Disable uninitialized warning for a local variable

C++ compilers emit warnings when a local variable may be uninitialized on first usage. However, sometimes, I know that the variable will always be written before being used, so I do not need to initialize it. When I do this, the compiler emits a warning, of course. Since my team is building with -Werror, the code will not compile. How can I turn off this warning for specific local variables. I have the following restrictions:
I am not allowed to change compiler flags
The solution must work on all compilers (i.e., no gnu-extensions or other compiler specific attributes)
I want to use this only on specific local variables. Other uninitialized locals should still trigger a warning
The solution should not generate any instructions.
I cannot alter the class of the local variable. I.e., I cannot simply add a "do nothing" constructor.
Of course, the easiest solution would be to initialize the variable. However, the variable is of a type that is costly to initialize (even default initialization is costly) and the code is used in a very hot loop, so I do not want to waste the CPU cycles for an initialization that is guaranteed to be overwritten before it is read anyway.
So is there a platform-independent, compiler-independent way of telling the compiler that a local variable does not need to be initialized?
Here is some example code that might trigger such a warning:
void foo(){
T t;
for(int i = 0; i < 100; i++){
if (i == 0) t = ...;
if (i == 1) doSomethingWith(t);
}
}
As you see, the first loop cycle initializes t and the second one uses it, so t will never be read uninitialized. However, the compiler is not able to deduce this, so it emits a warning. Note that this code is quite simplified for the sake of brevity.
My answer will recommend another approach: instead of disabling the warning code, just do some reformulation on the implementation. I see two approaches:
First Option
You can use pointers instead of a real object and guarantee that it will be initialized just when you need it, something like:
std::unique_ptr<T> t;
for(int i=0; i<100; i++)
{
if(i == 0) if(t.empty()) t = std::unique_ptr<T>(new T); *t = ...;
if(i == 1) if(t.empty()) t = std::unique_ptr<T>(new T); doSomethingWith(*t);
}
It's interesting to note that probably when i==0, you don't need to construct t using the default constructor. I can't guess how your operator= is implemented, but I supose that probably you are assigning an object that's already allocated in the code that you are omitting in the ... segment.
Second Option
As your code experiences such a huge performance loss, I can infer that T will never be an basic tipe (ints, floats, etc). So, instead of using pointers, you can reimplement your class T in a way that you use an init method and avoid initializing it on the constructor. You can use some boolean to indicate if the class needs initalization or not:
class FooClass()
{
public:
FooClass() : initialized(false){ ... }
//Class implementation
void init()
{
//Do your heavy initialization code here.
initialized = true;
}
bool initialized() const { return initialized; }
private:
bool initialized;
}
Than you will be able to write it like this:
T t;
for(int i=0; i<100; i++)
{
if(i == 0) if(!t.initialized()) t.init(); t = ...;
if(i == 1) if(!t.initialized()) t.init(); doSomethingWith(t);
}
If the code is not very complex, I usually unroll one of the iterations:
void foo(){
T t;
t = ...;
for(int i = 1; i < 100; i++){
doSomethingWith(t);
}
}

Array with pointers to objects initialization

I am currently working in C++ and I face this challenge. Here is a code of my class in the header file:
class PID
{
private:
int PID;
int total;
public:
PID(); // Constructor
int returnPID(); // Returns PID.
};
Here is the code declaration in cpp file:
PID::PID()
{
PID=INT_MAX;
total=0;
}
int PID::returnPID()
{
return PID;
}
And here is the declaration and the initialization in main of a table contaning pointers to objects of the class PID:
PID* table[1000000];
for (int i=0; i<1000000; i++)
{
table[i]=new PID;
}
So I suppose this uses the constructor I have created above to set the PID to MAX_INT. When I try to access the content of table[i].PID using returnPID within the initialization for everything works great, something like this:
for (int i=0; i<1000000; i++)
{
table[i]=new PID;
int display=table[i]->returnPID();
cout<<display<<endl;
}
The problem occurs when I am trying to access table[i] contents outside and after the initialization for. My main crashes and it returns a number (-1073741571) as an error. It seems like not even one command from the main is executed. Here is a sample of the code that seems to reproduce the problem:
for (int i=0; i<1000000; i++)
{
table[i]=new PID;
}
for (int i=0; i<1000000; i++)
{
int display=table[i]->returnPID();
cout<<display<<endl;
}
I have been working on this for more than two hours without coming to any solution and it just doesn't seem logical. Anyone have any explanation for this?
EDIT: Any table with less than 1.000.000 spots will work correctly. Maybe it has something to do with this although I still don't see the connection.
Anyone have any explanation for this?
It seems like you're running out of stack space.
Can your compiler handle a million integers, instead of a million PID*?
Any table with less than 1.000.000 spots will work correctly. Maybe it
has something to do with this although I still don't see the
connection.
It has everything to do with that.
I tried this:
int main(){
int bec[10000000];
for (int i=0; i<10000000;i++){
bec[i] = i;
}
printf("%d\n",rand()%1000);
return 0;
}
It segfaults for the same reason as yours.
The only way to solve this problem is to use less stack space. You can declare bec outside of main and not use stack space for that or you can use std::vector. You have plenty of options.
PID* table[1000000];
There's your problem. That's an automatically-allocated array of 1,000,000 pointers, or [up to] eight million bytes. Stack space is often fairly limited and you're using a lot of it. When I say "limited", I mean like 8KB, not 8MB.
When you go over this, often the results are not pretty.
8MB is a lot for automatic allocation (what you may call "on the stack"); so, look into adjusting your storage mechanism, or consider using dynamic allocation — how about a nice std::vector?
BTW.. having a member variable with the same name as the class it's in is silly.

Multithreaded matrix multiplication in C++

I've been having trouble with this parallel matrix multiplication code, I keep getting an error when trying to access a data member in my structure.
This is my main function:
struct arg_struct
{
int* arg1;
int* arg2;
int arg3;
int* arg4;
};
int main()
{
pthread_t allthreads[4];
int A [N*N];
int B [N*N];
int C [N*N];
randomMatrix(A);
randomMatrix(B);
printMatrix(A);
printMatrix(B);
struct arg_struct *args = (arg_struct*)malloc(sizeof(struct arg_struct));
args.arg1 = A;
args.arg2 = B;
int x;
for (int i = 0; i < 4; i++)
{
args.arg3 = i;
args.arg4 = C;
x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)args);
if(x!=0)
exit(1);
}
return 0;
}
and the matrixMultiplication method used from another C file:
void *matrixMultiplication(void* arguments)
{
struct arg_struct* args = (struct arg_struct*) arguments;
int block = args.arg3;
int* A = args.arg1;
int* B = args.arg2;
int* C = args->arg4;
free(args);
int startln = getStartLineFromBlock(block);
int startcol = getStartColumnFromBlock(block);
for (int i = startln; i < startln+(N/2); i++)
{
for (int j = startcol; j < startcol+(N/2); j++)
{
setMatrixValue(C,0,i,j);
for(int k = 0; k < N; k++)
{
C[i*N+j] += (getMatrixValue(A,i,k) * getMatrixValue(B,k,j));
usleep(1);
}
}
}
}
Another error I am getting is when creating the thread: "invalid conversion from ‘void ()(int, int*, int, int*)’ to ‘void* ()(void)’ [-fpermissive]
"
Can anyone please tell me what I'm doing wrong?
First you mix C and C++ very badly, either use plain C or use C++, in C++ you can simply use new and delete.
But the reason of your error is you allocate arg_struct in one place and free it in 4 threads. You should allocate one arg_struct for each thread
Big Boss is right in the sense that he has identified the problem, but to add to/augment the reply he made.
Option 1:
Just create an arg_struct in the loop and set the members, then pass it through:
for(...)
{
struct arg_struct *args = (arg_struct*)malloc(sizeof(struct arg_struct));
args->arg1 = A;
args->arg2 = B; //set up args as now...
...
x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)args);
....
}
keep the free call in the thread, but now you could then use the passed struct directly rather than creating locals in your thread.
Option 2:
It looks like you want to copy the params from the struct internally to the thread anyway so you don't need to dynamically allocate.
Just create an arg_struct and set the members, then pass it through:
arg_struct args;
//set up args as now...
for(...)
{
...
x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)&args);
}
Then remove the free call.
However as James pointed out you would need to synchronize in the thread/parent on the structure to make sure that it wasn't changed. That would mean a Mutex or some other mechanism. So probably the move of the allocation to the for loop is easier to begin with.
Part 2:
I'm working on windows (so I can't experiment currently), but pthread_create param 3 is referring to the thread function matrixMultiplication which is defined as void* matrixMultiplication( void* ); - it looks correct to me (signature wise) from the man pages online, void* fn (void* )
I think I'll have to defer to someone else on your second error. Made this post a comunnity wiki entry so answer can be put into this if desired.
It's not clear to me what you are trying to do. You start some threads,
then you return from main (exiting the process) before getting any
results from them.
In this case, I'ld probably not use any dynamic allocation, directly.
(I would use std::vector for the matrices, which would use dynamic
allocation internally.) There's no reason to dynamically allocate the
arg_struct, since it can safely be copied. Of course, you'll have to
wait until each thread has successfully extracted its data before
looping to construct the next thread. This would normally be done using
a conditional: the new thread would unblock the conditional once it has
extracted the arguments from the arg_struct (or even better, you could
use boost::thread, which does this part for you). Alternatively, you
could use an array of arg_struct, but there is absolutely no reason to
allocate them dynamically. (If for some reason you cannot use
std::vector for A, B and C, you will want to allocate these
dynamically, in order to avoid any risk of stack overflow. But
std::vector is a much better solution.)
Finally, of course, you must wait for all of the threads to finish
before leaving main. Otherwise, the threads will continue working on
data that doesn't exist any more. In this case, you should
pthread_join all of the threads before exiting main. Presumably,
too, you want to do something with the results of the multiplication,
but in any case, exiting main before all of the threads have finished
accessing the matrices will cause undefined behavior.