简体   繁体   中英

How do I synchronize the threads without using pthread_join()?

I have created a simple c++ program which is used for logging. I am creating threads in a for loop which runs 1000 times in test.cpp which is the driver file. pthread_create calls the print function in tt.cpp which writes the input parameter ie i, in file.txt . I wish to synchronize the threads.

I have tried using pthread_join which synchronized the threads but I wish to synchronize the threads without using join.

I know that if a thread is locked, a lot of threads will be waiting until it gets unlocked and after that thread is unlocked, any one of the waiting threads will lock the function. So, I tried to use a static integer variable in tt.cpp and tried to compare it with the input parameter so that I can use pthread_cond_wait and pthread_wait_signal but I got segmentation fault on comparing.

 /* if(j == *((int *)input)))
    This comparison gave me a segmentation fault */


-------------------------test.cpp---------------------------------
#include "thr.h"


pthread_mutex_t loc;
FILE *thePrintFile = NULL;

int main()
{
    pthread_mutex_init(&loc,NULL);

    pthread_t p;
    thePrintFile = fopen("file.txt","r+");
    for(int i =0; i<1000;i++)
    {
        pthread_create(&p,NULL,print,(void *)i);
    }
    for(int k = 0; k<100000;k++);
    /* i have used it to ensure that the main thread 
       doesn't exit before the pthreads finish writing */
    return 0;

}

    ------------------------tt.cpp------------------------------------
    #include "thr.h"

    extern pthread_mutex_t loc;
    extern FILE *thePrintFile;

    void* print(void *input)
    {
        if(pthread_mutex_trylock(&loc) == 0)
        {   

            fprintf(thePrintFile,"%s%d\n",(int *)input);
            fflush(thePrintFile);
            pthread_mutex_unlock(&loc);
        }   
    }

    -----------------------------thr.h--------------------------------
    #ifndef THR_H_INCLUDED
    #define THR_H_INCLUDED

    void* print(void *input);

    #endif

Given below is a part of file.txt .

1
5
9
10
11
12
13
14
15
16
18
19
20
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
21
201
202

To synchronize the threads properly, you need to use a synchronization device such as a condition variable . Since you are using C++, you are much better off using its built-in threads rather than the raw pthread API.

For example, this code synchronizes 1000 threads so that each prints its own ID using a condition variable and mutex pair to ensure that the IDs are printed in order, as tracked by a separate variable shared by all. It is not very efficient because all threads fight for the same mutex, but it works correctly. It could be made more efficient by creating a condition variable for each thread, but doing it correctly would require a better understanding of your actual use case.

#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <vector>

static std::mutex mutex;
static std::condition_variable condvar;
static int whos_next;

static void work(int id) {
  std::unique_lock<std::mutex> lock{mutex};
  // wait for our turn
  condvar.wait(lock, [=]() { return whos_next == id; });
  // it's our turn now - print our thread ID
  std::cout << id << '\n';
  ++whos_next;
  condvar.notify_all();    // notify the next thread to run
}

int main() {
  std::vector<std::thread> threads;
  for (int i = 0; i < 1000; i++)
    threads.push_back(std::thread([=]() { work(i); }));

  for (auto &t: threads)
    t.join();
}

Note that the above code's use of join is not to synchronize the threads with each other (they synchronize among themselves using the mutex/condition), but for its intended purpose: to wait for the threads to finish before exiting main() . C++ even requires that you do that before destructing the std::thread object, so removing the join results in program termination. You can easily prove that the threads don't rely on join for synchronization, eg by inserting a sleep before joins, or by joining them in reverse order.

I see multiple problems in your code.

  • You show that you get a segmentation fault on a certain line. That line is not in the actual code you posted.
  • You have a void * return type for your print section but you don't return anything.
  • You cast int to void *. The size of a pointer might not be the same as the size of int. Change your print function argument to be int instead. Then the cast is unnecessary.
  • You can't write with 1000 threads to the same file at the same time. So in this case there is no reason to create threads, because you have to execute them sequentially anyways. But if you do, then you have to join them.

Then let's look at the comparison you try to make:

if(j == *((int *)input)))

j is obviously int. input is void *. At the basis input was int. Because casting int to void * is not guaranteed to be safe, casting it back is not safe either. Imagine that int is 64bits and a pointer is 32bit. If you cast your int to void * you lose 32 bits. Then you cast from 32bit to 64bit, so you add 32bit of 0's. Obviously that is going to give problems.

Consider using C++11, that will greatly improve your code. https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM