POSIX线程同步和/或pthread_create()参数传递问题

时间:2014-10-19 15:55:06

标签: c++ multithreading semaphore

我正在尝试创建许多不同的线程,这些线程需要等待所有线程创建才能执行任何操作。这是一个大型程序的一小部分,我只是试图采取步骤。在创建每个线程时,它立即被信号量阻塞。在创建了所有线程之后,我遍历并释放所有线程。然后,我希望每个线程打印出它的线程号,以验证它们都等待。我只允许使用另一个信号量一次打印一个线程。

我遇到的问题是,虽然我创建了#1-10的线程,但是一个线程打印出它是#11。此外,一些主题说他们的数字与另一个相同。我传递threadID时是错误还是我的同步?

以下是相关代码:

//Initialize semaphore to 0. Then each time a thread is spawned it will call
    //semWait() making the value negative and blocking that thread. Once all of the
    //threads are created, semSignal() will be called to release each of the threads
     sem_init(&threadCreation,0,0);


     sem_init(&tester,0,1);


    //Spawn all of the opener threads, 1 for each valve
    pthread_t threads[T_Valve_Numbers];
    int check;

    //Loop starts at 1 instead of the standard 0 so that numbering of valves
    //is somewhat more logical. 
    for(int i =1; i <= T_Valve_Numbers;i++)
    {
        cout<<"Creating thread: "<<i<<endl;
        check=pthread_create(&threads[i], NULL, Valve_Handler,(void*)&i);
        if(check)
        {
            cout <<"Couldn't create thread "<<i<<" Error: "<<check<<endl;
            exit(-1);
        }
    }

    //Release all of the blocked threads now that they have all been created
    for(int i =1; i<=T_Valve_Numbers;i++)
    {
        sem_post(&threadCreation);
    }

    //Make the main process wait for all the threads before terminating
    for(int i =1; i<=T_Valve_Numbers;i++)
    {
        pthread_join(threads[i],NULL);
    }
    return 0;



}   
    void* Valve_Handler(void* threadNumArg)
    {   
        int threadNum = *((int *)threadNumArg);
        sem_wait(&threadCreation);//Blocks the thread until all are spawned

        sem_wait(&tester);
        cout<<"I'm thread "<<threadNum<<endl;
        sem_post(&tester);
    }

当T_Valve_Numbers = 10时,一些样本输出为:

Creating thread: 1
Creating thread: 2
Creating thread: 3
Creating thread: 4
Creating thread: 5
Creating thread: 6
Creating thread: 7
Creating thread: 8
Creating thread: 9
Creating thread: 10
I'm thread 11   //Where is 11 coming from?
I'm thread 8
I'm thread 3
I'm thread 4
I'm thread 10
I'm thread 9
I'm thread 7
I'm thread 3
I'm thread 6
I'm thread 6   //How do I have 2 6's?

OR

Creating thread: 1
Creating thread: 2
Creating thread: 3
Creating thread: 4
Creating thread: 5
Creating thread: 6
Creating thread: 7
Creating thread: 8
Creating thread: 9
Creating thread: 10
I'm thread 11
I'm thread 8
I'm thread 8
I'm thread 4
I'm thread 4
I'm thread 8
I'm thread 10
I'm thread 3
I'm thread 9
I'm thread 8 //Now '8' showed up 3 times

“我是线程......”正在打印10次,所以看起来我的信号量让所有线程都通过了。我只是不确定为什么他们的主题号码搞砸了。

1 个答案:

答案 0 :(得分:5)

check=pthread_create(&threads[i], NULL, Valve_Handler,(void*)&i);
                                                             ^^

您正在将线程启动函数传递给i的地址。 i在主循环中一直在变化,与线程函数不同步。一旦线程函数实际解除引用该指针,你就不知道i的值是什么。

传入实际的整数而不是指向局部变量的指针,如果这是你唯一需要传递的东西。否则,使用所有参数创建一个简单的struct,构建一个数组(每个线程一个),并为每个线程传递指向其自己元素的指针。

示例:(假设您的线程索引永远不会溢出int

#include <stdint.h> // for intptr_t

...
check = pthread_create(..., (void*)(intptr_t)i);
...

int threadNum = (intptr_t)threadNumArg;

更好/更灵活/不需要可能不存在的intprt_t示例:

struct thread_args {
  int thread_index;
  int thread_color;
  // ...
}

// ...

struct thread_args args[T_Valve_Numbers];
for (int i=0; i<T_Valve_Numbers; i++) {
  args[i].thread_index = i;
  args[i].thread_color = ...;
}

// ...

check = pthread_create(..., &(args[i-1])); // or loop from 0, less surprising

关于这一点需要注意的是:线程参数数组至少需要保持活动,只要线程将使用它。在某些情况下,您可能更好地为每个结构进行动态分配,将该指针(及其所有权)传递给线程函数(特别是如果您要分离线程而不是连接它们)。

如果您要在某个时刻加入线程,请保持这些参数与保持pthread_t结构的方式相同。 (如果你正在创建并加入相同的函数,那么堆栈通常很好。)