如何不使用pthread_join()同步线程?

时间:2019-06-15 08:36:52

标签: c++ synchronization pthreads mutex

我创建了一个简单的用于记录日志的c ++程序。我正在for循环中创建线程,该循环在驱动程序文件test.cpp中运行1000次。 pthread_create调用tt.cpp中的打印函数,该函数将输入参数(即i)写入file.txt中。 我希望同步线程。

我尝试使用pthread_join来同步线程,但是我希望不使用join来同步线程。

我知道,如果一个线程被锁定,那么很多线程将一直等待直到被解锁为止,并且在该线程被解锁之后,任何一个等待中的线程都会锁定该函数。因此,我尝试在tt.cpp中使用静态整数变量,并尝试将其与输入参数进行比较,以便可以使用pthread_cond_waitpthread_wait_signal,但是在比较时遇到了分段错误。 / p>

 /* 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

以下是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

2 个答案:

答案 0 :(得分:1)

我在您的代码中看到了多个问题。

  • 您表明在特定的行上遇到了分段错误。该行不在您发布的实际代码中。
  • 您的打印部分有一个void *返回类型,但是您什么也不返回。
  • 您将int转换为void *。指针的大小可能与int的大小不同。将您的打印函数参数更改为int。那么演员就没有必要了。
  • 您不能同时将1000个线程写入同一文件。因此,在这种情况下,没有理由创建线程,因为无论如何您都必须顺序执行它们。但是,如果这样做,则必须加入他们的行列。

然后让我们看一下您要进行的比较:

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

j显然是int。输入无效*。在基础上输入是int。因为不能保证将int强制转换为void *是安全的,所以将其强制返回也不安全。假设int是64位,而指针是32位。如果将int强制转换为void *,则会丢失32位。然后,您将32位转换为64位,因此将0的32位相加。显然这会带来问题。

考虑使用C ++ 11,这将大大改善您的代码。 https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

答案 1 :(得分:1)

要正确同步线程,您需要使用同步设备,例如condition variable。由于您使用的是C ++,因此最好使用其built-in threads而不是原始的pthread API。

例如,此代码同步1000个线程,以便每个线程都使用条件变量和互斥锁对打印其自己的ID,以确保按顺序打印ID,这是所有人共享的单独变量所跟踪的。由于所有线程都争用同一个互斥锁,所以效率不是很高,但是它可以正常工作。通过为每个线程创建一个条件变量可以提高效率,但是正确地执行它需要对您的实际用例有更好的了解。

#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();
}

请注意,以上代码对join的使用不是为了使线程彼此同步(它们使用互斥锁/条件在彼此之间进行同步),而是出于其预期的目的:等待线程完成之前,退出main()。 C ++甚至要求您在销毁std::thread对象之前执行此操作,因此删除联接会导致程序终止。您可以轻松证明线程不依赖join进行同步,例如通过在加入之前插入睡眠,或以相反的顺序加入它们。