Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C/C++;pthread信号和指针_C++_Multithreading_Pthreads - Fatal编程技术网

C++ C/C++;pthread信号和指针

C++ C/C++;pthread信号和指针,c++,multithreading,pthreads,C++,Multithreading,Pthreads,我最难理解的是如何让线程相互发出信号 我的设计: main函数创建一个主线程来协调一组其他工作线程。main函数还创建辅助线程,因为辅助线程以在main中编程的间隔生成和退出。主线程需要能够向这些工作线程发送信号,并向所有工作线程发送信号,同时工作线程也必须向主线程发回信号(pthread\u cond\u信号)。因为每个线程都需要一个pthread_互斥体和pthread_cond,所以我用这些变量创建了一个Worker类和一个Master类。这就是我被困的地方。C++不允许您将成员函数传递为

我最难理解的是如何让线程相互发出信号

我的设计:

main函数创建一个主线程来协调一组其他工作线程。main函数还创建辅助线程,因为辅助线程以在main中编程的间隔生成和退出。主线程需要能够向这些工作线程发送信号,并向所有工作线程发送信号,同时工作线程也必须向主线程发回信号(pthread\u cond\u信号)。因为每个线程都需要一个pthread_互斥体和pthread_cond,所以我用这些变量创建了一个Worker类和一个Master类。这就是我被困的地方。C++不允许您将成员函数传递为pthRead创建(…)处理程序,因此我必须在内部生成一个静态处理器,并将指针传递给它自己,以重新解释它使用它的类数据…< /p>
void Worker::start() {
pthread_create(&thread, NULL, &Worker::run, this);
}

void* Worker::run(void *ptr) {
Worker* data = reinterpret_cast<Worker*>(ptr);
}

仍然不起作用。

不清楚您的具体情况,但似乎您正在使用容器来保存在
main
中创建的“Worker”实例,并将它们传递给您的“Master”。如果是这种情况,您可以使用一些补救措施。您需要选择一个适合您的实现的

  • main
    中容器的引用传递给主机
  • 将容器更改为包含指向辅助对象的(智能)指针
  • 使容器成为“Master”本身的一部分,这样就不需要传递给它
  • 为您的工人类实现适当的析构函数、复制构造函数和赋值运算符(换句话说,遵守规则)
从技术上讲,由于
pthread\u create()
是一个C API,因此传递给它的函数指针需要有C链接(
extern“C”
)。你不能让C++类的方法有C链接,所以你应该定义一个外部函数:

extern "C" { static void * worker_run (void *arg); }

class Worker { //...
};

static void * worker_run (void *arg) {
    return Worker::run(arg);
}
编辑修复了所有版本中的潜在竞争:

1./1b使用一个由(互斥+条件+计数器)构建的符号库,如
2.使用“反向”等待,以确保目标工人确认信号

我真的建议使用c++11风格的
来实现这一点

我有两个(半)演示。他们每个人都假设你有一台主机,可以驱动10名工人。每个工人在工作前都会等待信号

我们将使用
std::condition\u变量
(它与
std::mutex
一起工作)来发送信号。第一个版本和第二个版本之间的区别在于发送信号的方式:

  • 一,。一次通知一名工人:
  • 1b。使用worker结构
  • 二,。通知所有线程,协调要响应的收件人工作线程
1.一次通知一名工人: 这是最简单的方法,因为几乎没有协调:

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

using namespace std;

class semaphore 
{ // see https://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads
    std::mutex mx;
    std::condition_variable cv;
    unsigned long count;
public:
    semaphore() : count() {} 
    void notify();
    void wait();
};

static void run(int id, struct master& m);

struct master
{
    mutable semaphore sem;

    master()
    {
        for (int i = 0; i<10; ++i)
            threads.emplace_back(run, i, ref(*this));
    }

    ~master() {
        for(auto& th : threads) if (th.joinable()) th.join(); 
        std::cout << "done\n";
    }

    void drive()
    {
        // do wakeups
        for (unsigned i = 0; i<threads.size(); ++i)
        {
            this_thread::sleep_for(chrono::milliseconds(rand()%100));
            sem.notify();
        }
    }

  private:
    vector<thread> threads;
};

static void run(int id, master& m)
{
    m.sem.wait();
    {
        static mutex io_mx;
        lock_guard<mutex> lk(io_mx);
        cout << "signaled: " << id << "\n";
    }
}

int main()
{
    master instance;
    instance.drive();
}

/// semaphore members
void semaphore::notify()
{
    lock_guard<mutex> lk(mx);
    ++count;
    cv.notify_one();
}

void semaphore::wait()
{
    unique_lock<mutex> lk(mx);
    while(!count)
        cv.wait(lk);
    --count;
}
警告
  • cv.wait()。在任何平台上,条件变量都会发生这种情况
    
以下方法解决了这一问题:

2.通知所有线程,协调哪个收件人工作线程 使用标志来表示哪个线程将接收信号:

struct master
{
    mutable mutex mx;
    mutable condition_variable cv;
    int signaled_id;               // ADDED

    master() : signaled_id(-1)
    {
让我们假设
driver
变得更加有趣,并希望以特定(随机…)顺序向所有工人发出信号:

这结束了虚假的觉醒

完整代码列表/现场演示:
  • 1。通知_one.cpp
  • 1b.id.
    工作者
    struct
  • 2。通知所有人.cpp

您的启动看起来很好-
重新解释\u cast
静态\u cast
在这种情况下应该做同样的事情,因为您是从
void*
进行铸造的。我认为可能的问题是,您有
pthread\u mutex\t
成员变量,您在初始化后复制/移动这些变量,这是严格禁止的。你是否在你的
主/工作者
类中禁用了复制构造?我尝试过,但是:私人工作者(const-Worker&);工作者运算符=(常数工作者&);给我一个错误:“Worker-Worker::operator=(const-Worker&)”是私有的。如果将指针数组传递给主线程,则不应调用复制构造函数。@user622469这不是您所期望的吗?将其私有化的目的正是为了发生这种错误。该错误显示(在编译时)正在该位置调用Worker的赋值运算符。您需要绕过通常通过值传递/返回或直接存储在容器中的问题。我认为您的
signal()
方案具有
signaled\u id
,在主线程可以在最后一个发出信号的线程有机会读取
signalu id
之前向第二个线程发出信号的情况下,存在争用条件。这是一种在测试场景中可能看不到的情况,但如果您不采取具体措施加以防止,几乎肯定会在实际运行中看到。类似地,如果线程在调用
条件变量::wait()
(持有锁时)之前未检查
已发出信号的\u id
,它将丢失其信号。@MichaelBurr由于
等待
在等待期间锁定/解锁互斥锁的方式,这无法发生。见下文1)。(第二个问题可能是一个问题,具体取决于应用程序。您可以通过在创建线程之前/期间锁定互斥来轻松解决。)由于您调用了
notify_all()
,我假设可能会释放多个等待的线程。当目标线程正在等待获取互斥体时,主线程可能会出现,获取互斥体并更改
信号_id
。没有FIF的保证
struct worker
{
    worker(int id) : id(id) {}

    void run(master& m) const;

    int id;
};

// ...
struct master
{
    // ...

    master()
    {
        for (int i = 0; i<10; ++i)
            workers.emplace_back(i);

        for (auto& w: workers)
            threads.emplace_back(&worker::run, ref(w), ref(*this));
    }

// ...

void worker::run(master& m) const
{
    m.sem.wait();
    {
        static mutex io_mx;
        lock_guard<mutex> lk(io_mx);
        cout << "signaled: " << id << "\n";
    }
}
struct master
{
    mutable mutex mx;
    mutable condition_variable cv;
    int signaled_id;               // ADDED

    master() : signaled_id(-1)
    {
    void drive()
    {
        // generate random wakeup order
        vector<int> wakeups(10);
        iota(begin(wakeups), end(wakeups), 0);
        random_shuffle(begin(wakeups), end(wakeups));

        // do wakeups
        for (int id : wakeups)
        {
            this_thread::sleep_for(chrono::milliseconds(rand()%1000));
            signal(id);
        }
    }

  private:
    void signal(int id)                // ADDED id
    {
        unique_lock<mutex> lk(mx);

        std::cout << "signaling " << id << "\n";

        signaled_id = id;              // ADDED put it in the shared field
        cv.notify_all();

        cv.wait(lk, [&] { return signaled_id == -1; });
    }
m.cv.wait(lk, [&] { return m.signaled_id == id; });
m.signaled_id = -1;
m.cv.notify_all();