0

我正在学习多线程。关于

http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SCHEDULING

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;



void *functionCount1();
void *functionCount2();

int  count = 0;

#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6



main()
{
   pthread_t thread1, thread2;
   pthread_create( &thread1, NULL, &functionCount1, NULL);
   pthread_create( &thread2, NULL, &functionCount2, NULL);



   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   printf("Final count: %d\n",count);

   exit(0);
}



// Write numbers 1-3 and 8-10 as permitted by functionCount2()

void *functionCount1()
{
   for(;;)
   {
      // Lock mutex and then wait for signal to relase mutex
      pthread_mutex_lock( &count_mutex );



      // Wait while functionCount2() operates on count
      // mutex unlocked if condition varialbe in functionCount2() signaled.

      pthread_cond_wait( &condition_var, &count_mutex );

      count++;

      printf("Counter value functionCount1: %d\n",count);
      pthread_mutex_unlock( &count_mutex );

      if(count >= COUNT_DONE) return(NULL);
    }
}



// Write numbers 4-7



void *functionCount2()
{
   for(;;)
    {
       pthread_mutex_lock( &count_mutex );

       if( count < COUNT_HALT1 || count > COUNT_HALT2 )
       {
          // Condition of if statement has been met.
          // Signal to free waiting thread by freeing the mutex.
          // Note: functionCount1() is now permitted to modify "count".

          pthread_cond_signal( &condition_var );
       }
       else
       {
          count++;
          printf("Counter value functionCount2: %d\n",count);
       }



       pthread_mutex_unlock( &count_mutex );

       if(count >= COUNT_DONE) return(NULL);
    }
}

我想知道代码的控制流程。

作为pthread_cond_wait - unlocks the mutex and waits for the condition variable cond to be signaled

我对流量控制的理解是

1)创建线程一,线程二,并通过线程1控制(考虑单核处理器系统)

2)当它pthread_cond_wait( &condition_var, &count_mutex );thread1例程中遇到时void *functionCount1()- 它释放锁并进入等待状态,将控制权传递给thread2 void *functionCount1()

3)检查thread2变量count,因为它满足count < COUNT_HALT1 || count > COUNT_HALT2- 它发出信号thread1并重新启动是递增count

4)重复Steps 2 to 3显示1-3thread1

5)因为thread2在行动,和count 4-7之间没有切换thread1thread2

6) For count 8-10againsteps 2-3被重复。

我想知道我的理解是否正确?是否thread1进入睡眠并将thread2其唤醒(即线程已切换)count value 1-3 and 8-10 i.e switching between threads happen 5 times

编辑

我要问这个问题的主要关注点是知道它是否会在遇到时thread1进入状态并且不会再次出现,除非发出信号,然后才会递增,即它不会一次性递增,而是每次递增,它必须等待只有这样的信号才能继续进行sleeppthread_cond_wait( &condition_var, &count_mutex );activethread2count1-3thread2

4

3 回答 3

3

第一:拿到布滕霍夫的书,然后学习。您引用的页面有几个地方不正确,作者显然不了解线程自己。

关于您的问题:首先要说的是您无法了解代码的控制流。这是线程的一个特点,在现代处理器上,您经常会发现线程真正并行运行,一个内核执行一个线程,另一个内核执行另一个。在每个线程中,处理器可能会以意想不到的方式重新安排内存访问。例如,这就是您需要互斥锁的原因。(您提到“考虑单核处理系统”,但实际上,单核通用系统已不存在。)

其次,如何调度线程取决于操作系统。例如,在您的代码中,functionCount2可以在开始之前运行直到完成functionCount1,这意味着functionCount1它将永远等待。

第三,一个线程pthread_cond_wait可能被虚假唤醒。这是pthread_cond_wait一个循环中的绝对规则,它检查您实际等待的任何条件。也许是这样的:

while ( count > COUNT_HALT1 && count < COUNT_HALT2 ) {
    pthread_cond_wait( &condition_var, &count_mutex );
}

最后,有时,您正在访问count不受互斥锁保护的部分。这是未定义的行为;所有 访问都count必须受到保护。在您的情况下,锁定和解锁可能应该在程序循环之外,并且两个线程都应该等待条件变量。(但这显然是一种人为的情况——在实践中,几乎总是会有一个生产者线程和一个消费者线程。)

于 2013-05-15T08:56:49.103 回答
2

在理想世界中,是的,但在实践中,并不完全如此。

您无法预测哪个胎面首先获得控制权。是的,很可能是thread1,但仍不能保证。这是代码中的第一个竞速条件。

thread2获得控制权时,它很可能会不停地完成。不管你有多少个 CPU。原因是它没有yield 无条件的地方。您 release 的事实mutex并不意味着 any1 可以锁定它。它是您代码中的第二个赛车条件。

因此,thread1将打印11,这是唯一保证的部分。

于 2013-05-15T08:06:05.380 回答
1

1) 创建线程。控制权不会传递给 thread1,而是由系统调度程序决定执行哪个线程。两个线程都处于活动状态,都应该接收处理器时间,但顺序不确定。可能有几个上下文切换,你并不能真正控制它。

2) 正确,thread1进入等待状态,thread2继续工作。同样,控制没有明确传递。

3) 是的,thread2 通知条件变量,因此 thread1 将唤醒并尝试重新获取互斥锁。控制不会立即转到线程 1。

一般来说,您应该了解您无法真正控制要执行的线程。这是系统调度程序的工作,它可以根据需要放置尽可能多的上下文切换。

UPD:使用条件变量,您可以控制多线程环境中任务执行的顺序。所以我认为你的理解或多或少是正确的:thread1 正在等待来自 thread2 的信号的条件变量。当收到信号时,thread1 继续执行(在它重新获取互斥锁之后)。但是在线程之间切换 - 可能有很多线程,5 只是理论上的最小值。

于 2013-05-15T08:07:08.853 回答