【问题标题】:pthread loop overwriting pointerspthread 循环覆盖指针
【发布时间】:2013-07-19 16:22:42
【问题描述】:

我正在编写一个带有类、pthread、互斥锁和 conds 的简单理发店 C/C++ 项目,但是当我在循环中创建新客户对象时遇到了问题:

void BarberShop::simulate() {
barber.start(); // start the barber
int custId = 1;
while(1) {
    Customer c(custId, *this);
    customers.push_back(c);
    c.start();
    sleep(3);
    custId++;
}

}

void Customer::start() {
    pthread_create(&thread, NULL, &Customer::run, this);
}

void* Customer::run(void *ptr) {
    Customer* data = reinterpret_cast<Customer*>(ptr);
    while(1) {
        printf("Customer %d running...\n", data->id);
        sleep(3);
    }
}

当我运行这个程序时,它会很好地创建线程,但每当我创建一个新线程时,它会覆盖其他线程中的 id。输出:

Customer 1 running... 1 sec
Customer 1 running... 2 sec
Customer 1 running... 3 sec
Customer 2 running... 4 sec
Customer 2 running... 4 sec

在循环中我说:

Customer c(...);

这不是每次循环迭代都会创建一个新实例吗?为什么后面的线程会覆盖这个?

更新

class Customer
{
private:
    pthread_t thread;
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    static void* run(void *args);
    int id;
    BarberShop *bs;
public:
    Customer(int _id, BarberShop &_bs);
    ~Customer();
    void start();
}; 

Customer::Customer(int _id, BarberShop &_bs) {
id = _id;
bs = &_bs;
}

更新 2:使用 pthread id

Customer 1 running...[3066383168]
Customer 2 running...[3057990464]
Customer 2 running...[3057990464]
Customer 3 running...[3049597760]
Customer 3 running...[3049597760]
Customer 3 running...[3049597760]
Customer 3 running...[3049597760]
Customer 4 running...[3049597760]
Customer 4 running...[3041205056]
Customer 4 running...[3041205056]
Customer 4 running...[3041205056]
Customer 5 running...[3041205056]
Customer 4 running...[3041205056]
Customer 5 running...[3032812352]
Customer 5 running...[3032812352]

【问题讨论】:

  • 您没有将客户 ID 作为静态成员变量存储在您的类中,是吗?你能显示你的构造函数的代码吗?
  • 始终是同一个客户,在同一个地方,在同一个堆栈上。
  • 复制或移动pthread_mutex_t 不是定义的行为。您应该禁用 Customer 的复制构造和分配 - 这当然意味着您不能将它们放在 vector 中。请改用vector&lt;Customer*&gt;
  • @Martin James...呵呵!是的好地方。 +1

标签: c++ multithreading pthreads


【解决方案1】:

基于堆栈的自动对象和多线程是错误的。'在所有情况下都不和谐':)

您可以按照 Casey 的建议使用 Customer* 的向量。如果要通过引用将对象传递给线程,请使用 new 动态分配它们。这解决了同步对象的不可复制性等问题,并确保每个线程都有自己的*对象。线程获得所有权,如果它需要在进程终止之前终止,则需要删除传递的 *object。

或者,vector::emplace 将 Customer 对象放入向量中,以便自动/堆栈 Customer 消失。

【讨论】:

    【解决方案2】:

    在下面的片段中

    while(1) {
        Customer c(custId, *this);
        customers.push_back(c);
        c.start();
        sleep(3);
        custId++;
    }
    

    类实例c 在while 循环的范围内是本地的。在循环的每次迭代结束时,c 被销毁。

    因此,当您执行customers.push_back(c) 时,该课程的副本 会被获取(请参阅(default) copy constructor)并添加到客户列表中。这意味着当您执行c.start() 时,您推送到向量上的副本没有启动,只有循环本地的实例。在循环c 的循环迭代结束时被销毁。循环再次开始,并创建了一个新的c

    编辑: 请参阅 Martin James 和 Casey 的 cmets,了解您所看到的行为发生的原因

    【讨论】:

    • 其实……我错了……这正是问题所在。而不是 c.start() 我需要:customers[customers.size()-1].start();谢谢!
    • 我认为你错过了 Casey 和 MartinJames 提出的几点。
    猜你喜欢
    • 1970-01-01
    • 2014-09-02
    • 2015-12-23
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 2020-05-05
    相关资源
    最近更新 更多