Thread: multithreading and stl

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    222

    multithreading and stl

    Hi,

    so now i am playing around with threading. I have written a peace of code to thread a process into two threads. each thread working with a different variable type. However this seam to me too c-ish. so I was wondering is there a better way to do this? Is it possible to write down only one template function for printing instead of print_32 and print_64?

    Code:
    #include <iostream>
    #include <stdlib.h>
    #include <pthread.h>
    
    using namespace std;
    
    #define NUM_THREADS     2
    
    struct t{
    	int id;
    	char *string;
    };
    
    struct z{
    	long long id;
    	char *string;
    };
    
    void *print_32(void *st){
       int i;
       
       t *my_data;
       my_data = (struct t *) st;
       sleep(my_data->id+my_data->id);
       cout << "Thread with id : " << my_data->id << "\t"<< my_data->string<<"  ...exiting " << endl;
       pthread_exit(NULL);
    }
    void *print_64(void *st){
       int i;
       
       z *my_data;
       my_data = (struct z *) st;
       sleep(my_data->id+my_data->id);
       cout << "Thread with id : " << my_data->id << "\t"<< my_data->string<<"  ...exiting " << endl;
       pthread_exit(NULL);
    }
    
    int main ()
    {
       int rc;
       int i;
       pthread_t threads[NUM_THREADS];
       pthread_attr_t attr;
       t in;
       z in2;
       void *status;
    
       in.id = 2;
       in.string = "string 21\n";
       in2.id = 6;
       in2.string = "string 61\n";
       
       // Initialize and set thread joinable
       pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    
       cout << "main() : creating thread, " << 0 << endl;
       rc = pthread_create(&threads[0], NULL, print_32, &in);
       if (rc){
          cout << "Error:unable to create thread," << rc << endl;
          exit(-1);
       }
       cout << "main() : creating thread, " << 1 << endl;
       rc = pthread_create(&threads[1], NULL, print_64, &in2);
       if (rc){
          cout << "Error:unable to create thread," << rc << endl;
          exit(-1);
       }
    
       // free attribute and wait for the other threads
       pthread_attr_destroy(&attr);
       for( i=0; i < NUM_THREADS; i++ ){
          rc = pthread_join(threads[i], &status);
          if (rc){
             cout << "Error:unable to join," << rc << endl;
             exit(-1);
          }
          cout << "Main: completed thread id :" << i ;
          cout << "  exiting with status :" << status << endl;
       }
    
       cout << "Done" << endl;
       pthread_exit(NULL);
    }
    Thank you

    baxy

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Code:
    #include <thread>
    #include <string>
    #include <iostream>
    #include <mutex>
    
    struct example_t
    {
    	std::string str;
    	int id;
    };
    
    std::mutex g_CoutLock;
    
    void foo(const example_t& example)
    {
    	std::lock_guard<std::mutex> _(g_CoutLock);
    	std::cout << "Hello! I am thread " << example.id << ", and I wanted to say: " << example.str << "! Bye!\n";
    }
    
    int main()
    {
    	example_t e1 = { "Hello World", 1 };
    	example_t e2 = { "I hate you world", 2 };
    	std::thread t1(&foo, e1);
    	std::thread t2(&foo, e2);
    	t1.join();
    	t2.join();
    }
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    wow, thnx!!!!


    baxy

  4. #4
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    wow, thnx!!

    PS.

    Is it possible to do something like this

    Code:
    #include <thread>
    #include <string>
    #include <iostream>
    #include <mutex>
     
    struct example_t
    {
        std::string str;
        int id;
    };
    
    struct example_z
    {
        std::string str;
        long long id;
    };
    
    
    std::mutex g_CoutLock;
    
    template<typename T>
    void foo(T const& example)
    {
        std::lock_guard<std::mutex> _(g_CoutLock);
        
        std::cout << "Hello! I am thread " << example.id << ", and I wanted to say: " << example.str << "! Bye!\n";
    }
     
    int main(){
    	
        example_z e1 = { "Hello World", 90000000 };
        example_t e2 = { "I hate you world", 2 };
        
        
        std::thread t1(&foo, e1);
        std::thread t2(&foo, e2);
        t1.join();
        t2.join();
    }
    this is obviously not working!
    Last edited by baxy; 12-13-2012 at 08:15 AM.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You need to specify the type of foo in order for the compiler to understand the address of which function you are calling:
    Code:
    #include <thread>
    #include <string>
    #include <iostream>
    #include <mutex>
      
    struct example_t
    {
        std::string str;
        int id;
    };
     
    struct example_z
    {
        std::string str;
        long long id;
    };
     
     
    std::mutex g_CoutLock;
     
    template<typename T>
    void foo(T const& example)
    {
        std::lock_guard<std::mutex> _(g_CoutLock);
         
        std::cout << "Hello! I am thread " << example.id << ", and I wanted to say: " << example.str << "! Bye!\n";
    }
      
    int main(){
         
        example_z e1 = { "Hello World", 90000000 };
        example_t e2 = { "I hate you world", 2 };
         
         
        std::thread t1(&foo<example_z>, e1);
        std::thread t2(&foo<example_t>, e2);
        t1.join();
        t2.join();
    }
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    another problem.

    example:

    Code:
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    #include <time.h>
    #include <thread>
    #include <mutex>
    
    using namespace std;
    
    struct xx{
    	int a;
    };
    
    template<typename T>
    void foo(T& a){
      a.a = 10;
    }
    
    int main (){
      xx a;
      a.a=1;
      
      std::thread t1(&foo<xx>, a);
      t1.join();
      cout << a.a<<" \n";
      
    return 0;
    }
    is there a way to be able to modify the variables on the structure. This works when i am not threading but when i am, it is not.

    in the example above i get for a.a = 1 and am expecting 10.

    thread-free example
    Code:
    using namespace std;
    
    struct xx{
    	int a;
    };
    
    template<typename T>
    void foo(T & a){
      a.a = 10;
    }
    
    int main (){
      xx a;
      a.a=1;
      
      foo(a);
    
      cout << a.a<<" \n";
      
    return 0;
    }
    here i get 10 for a.a.


    thank you

    baxy

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    According to std::thread::thread - cppreference.com, all parameters passed to a thread are copied into thread local storage (makes sense since it makes for better cache coherency).
    If you absolutely must ciruimvent this restriction, you can use std::ref:

    Code:
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <cstring>
    #include <time.h>
    #include <thread>
    #include <mutex>
    #include <functional>
    
    using namespace std;
    
    struct xx{
    	int a;
    };
    
    template<typename T>
    void foo(T& a){
    	a.a = 10;
    }
    
    int main (){
    	xx a;
    	a.a=1;
    
    	std::thread t1(&foo<xx>, std::ref(a));
    	t1.join();
    	cout << a.a<<" \n";
    
    	return 0;
    }
    Don't forget to include <functional>.
    However, it may be better to use std::async instead (see example): std::async - cppreference.com
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    ok i either don't understand threads or they don't work for me. I was under the impression that if i thread a process into 2, then i will achieve ~2 fold faster performance. however after putting it all together and testing it , now at the end of the day i see no speed gain, in fact my computation is now even slower, 20( sec to be more precise ~3-4%). Before i have always used forks because results of my computations were written down into files so i didn't have to trouble myself with sharing memory and things like that, but now i need them to be written into memory (different memory locations) so i decided to use threads. However the speed is the most important. Is there a way to create two int arrays, process each array on one cpu/thread so that processing is twice as fast as the sequential processing and then write the results back into two different separate int arrays in memory.


    And thank you Elysia !!!!

    PS

    I am working on Ubuntu gcc 4.6.3, also i see only one cpu running
    Last edited by baxy; 12-13-2012 at 11:14 AM. Reason: PS

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    If you only see one cpu running, then there is something wrong in your code.
    Perhaps you should try to minimize your code to such extent that any further simplifying would destroy the observed behaviour, and then post it here.
    Don't lose heart; multi-threading is hard.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    ok so the problem is in making the whole thing thread safe. i don't quite understand mutual exclusion and locking. So let me just give an example:


    Code:
    using namespace std;
    std::mutex g_CoutLock;
    struct xx{
    	int a;
    };
    
    template<typename T>
    void foo(T& a){
    	
    	std::lock_guard<std::mutex> lock(g_CoutLock);
      for(int i = 0;i<100000;i++)
        for(int i =0;i< 100000;i++);
      
    }
    
    int main (){
      xx a;
      xx b;
      a.a=1;
      
      std::thread t1(&foo<xx>, a);
      std::thread t2(&foo<xx>, b);
      t1.join();
      t2.join();
      cout << a.a <<" \n";
      
    return 0;
    }
    in this way my two threads are behaving sequentially, i mean they execute sequentially. but if i move my mutex into the block or delete the complete lock, it behaves as i expect, it runs in parallel:


    Code:
    using namespace std;
    
    struct xx{
    	int a;
    };
    
    template<typename T>
    void foo(T& a){
    	std::mutex g_CoutLock;
    	std::lock_guard<std::mutex> lock(g_CoutLock);
      for(int i = 0;i<100000;i++)
        for(int i =0;i< 100000;i++);
      
    }
    
    int main (){
      xx a;
      xx b;
      a.a=1;
      
      std::thread t1(&foo<xx>, a);
      std::thread t2(&foo<xx>, b);
      t1.join();
      t2.join();
      cout << a.a <<" \n";
      
    return 0;
    }
    but is it thread-safe now ??

    baxy

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This is not thread safe.
    Mutex is the "resource" that both threads want to access. Mutex is the thing that you lock. std::lock_guard simply locks the mutex and unlocks when it goes out of scope. Thus, mutex must be accessible to both threads (it must not be a local copy).
    The idea is to lock when you need to access a shared resource and unlock after.
    Example:

    Code:
    #include <mutex>
    #include <thread>
    #include <functional>
    #include <iostream>
    #include <utility>
    
    struct xx
    {
    	xx(int n): a(n) {}
    	int a;
    	std::mutex m_Lock;
    };
    
    typedef std::lock_guard<std::mutex> lock_t;
    
    template<typename T>
    void foo(T& a, int thread)
    {
    	for (int i = 0; i < 10; i++)
    	{
    		lock_t lock(a.m_Lock); // Lock our "a"
    		std::cout << "Thread " << thread << ": a is " << ++a.a << std::endl;
    	}
    }
    
    int main ()
    {
    	xx a(1);
    
    	std::thread t1(&foo<xx>, std::ref(a), 1);
    	std::thread t2(&foo<xx>, std::ref(a), 2);
    	t1.join();
    	t2.join();
    
    	return 0;
    }
    Last edited by Elysia; 12-13-2012 at 12:53 PM. Reason: Better example; associate mutex with a variable
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Jan 2011
    Posts
    222
    Thank you !!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multithreading.
    By kevinawad in forum C++ Programming
    Replies: 5
    Last Post: 10-21-2008, 12:12 PM
  2. Multithreading
    By JaWiB in forum Game Programming
    Replies: 7
    Last Post: 08-24-2003, 09:28 PM
  3. Multithreading
    By Lord CyKill in forum C++ Programming
    Replies: 4
    Last Post: 06-30-2003, 11:14 AM
  4. Multithreading
    By -KEN- in forum C# Programming
    Replies: 4
    Last Post: 06-13-2003, 10:11 PM
  5. multithreading
    By thedumbmutt in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 11-13-2002, 11:54 AM