C pthreads Mutex没有按预期工作

时间:2014-05-22 12:59:33

标签: multithreading mutex

void *printing(void*);
pthread_mutex_t lock;

int main()
{
    pthread_t thrA,thrB,thrC;
    int num1=1,num2=2,num3=3;

    pthread_create(&thrA, NULL,*printing,(void*)num1 );
    pthread_create(&thrB, NULL,*printing, (void*)num2);
    pthread_create(&thrC, NULL,*printing, (void*)num3);

    pthread_join(thrA,NULL);
    pthread_join(thrB,NULL);
    pthread_join(thrC,NULL);

    pthread_mutex_destroy (&lock);

    return 0;
}

void *printing(void*param)
{

    int *num; //int pointer to receive void pass
    num = (int *) param; //assign void array to int array


    int k;
    for (k=0; k<3; k++)
    {
        pthread_mutex_lock (&lock);
        sleep((rand() % 10)/10);
        printf("%d",num);
        pthread_mutex_unlock(&lock);
        printf("  ");
    }


    pthread_exit(NULL);
}

我得到的输出是2 2 2 3 3 3 1 1 1或有时2 2 2 1 1 1 3 3 3或1 1 1 3 3 3 2 2 2
但我希望订单总是1 1 1 2 2 2 3 3 3 代码在受保护的部分(互斥锁)中休眠一些随机时间,以便下一个线程在此期间打印其编号。 问题出在哪儿?我怎样才能控制哪个线程首先运行?

3 个答案:

答案 0 :(得分:0)

创建的第一个线程运行并获取互斥锁上的锁定,休眠,写入1然后解锁互斥锁。

输出:1

在第一个线程解锁互斥锁之前,另外两个线程运行并等待互斥锁解锁。

在第一个线程解锁互斥锁之后,等待互斥锁的另外两个线程中的一个可以获得锁定。在您的情况下,线程2获取锁定,可能是第一个开始等待互斥锁,但不保证等待线程获取锁定的顺序,请参阅Order of execution of waiting threads blocked by mutex

因此,第2个线程获取锁定,休眠,写入1并解锁互斥锁。

输出:1 1

与此同时,线程1返回到循环的开头并等待互斥锁。

在第二个线程解锁互斥锁之后,等待锁定(1和3)的另外两个线程中的一个可以立即获取它。在你的情况下,线程3获得了锁定。

因此,第3号线获得锁定,休眠,写入1并解锁互斥锁。

输出:1 1 1

依旧等等。

答案 1 :(得分:0)

首先,要么我错过了什么,要么你的问题是错的。你建议&#34;代码在受保护的部分(互斥锁)中休眠一些随机时间,以便下一个线程在那段时间打印它的号码&#34;并说你因此期望&#34; 1 2 3 ...&#34;。这是矛盾的,如果每个线程都等待其他线程,他们会轮流打印&#34; 1 1 2 2 2 2 ...&#34;正如你所说的那样。 (但那真的是原因。)

其次,您似乎对互斥体的工作方式感到困惑。 SlappyTheFish解释得很好,所以我想我不需要打扰。但是我不确定SlappyTheFish解释的行为是否保证,即使它确实是你在测试中得到的,并且可能在实践中几乎所有情况下都会发生,但是当你使用线程时,你应该将它们视为完全独立的计算,实际上甚至可能并行运行。只有当某个线程阻塞并等待其他线程中的某些事情发生时,它才能保证该线程将运行并完成正在等待的工作。优化编译器和复杂的CPU可以对线程之间的精确执行顺序做很疯狂的事情,这样除非明确使用同步机制,否则永远不能依赖任何行为。如果我没有弄错的话,在第一个线程连续三次获得互斥锁之前,其他线程可以获得它之前也可能发生错误。您的代码未明确指定任何禁止此内容的内容。

答案 2 :(得分:0)

int k;
for (k=0; k<3; k++)
{
    pthread_mutex_lock (&lock);
    sleep((rand() % 10)/10);
    printf("%d",num);
    pthread_mutex_unlock(&lock);
    printf("  ");
}

这里有两个问题。

  1. 一旦你产生线程,就无法知道它们何时,甚至以何种顺序在CPU上进行调度,系统调度程序可以自由地做任何它认为是最好的选择。因此无保证具有num = 1的线程将是第一个被安排的线程。

  2. 你的sleep()调用是在关键部分(即锁定和解锁之间),因此线程在持有互斥锁时会睡眠,使得睡眠几乎无用,因为其他线程在睡眠时间内无法执行任何操作。一旦线程最终释放互斥锁,同一个线程就会循环并几乎立即再次调用pthread_mutex_lock()。

  3. 请注意,互斥锁并不真正用于控制线程执行顺序,它们意味着保护多个线程同时访问同一个变量。条件变量或信号量可能适合您尝试执行的操作。

    您可能还想使用printf("%d\n",num)(即添加换行符),因为I / O在大多数系统上都是缓冲的。虽然这不应该成为一个问题,但如果您试图了解正在发生的事情,可能会造成一些混乱。

    这里有一些对我有用的东西(除了第一个线程不一定是第一个(见1.))

    for (k=0; k<3; k++)
    {
      sleep(1); 
      pthread_mutex_lock (&lock);
      printf("%d\n",num);
      pthread_mutex_unlock(&lock);
    }
    pthread_exit(NULL);
    

    输出:   2   1   3   2   1   3   2   1   3

    再一次,这不是保证;