sched_yield() 如何在两个 pthread 之间工作?

How does sched_yield() work between two pthreads?

我是这个概念的新手,有点困惑。假设我想 运行 在单个内核上使用两个 pthread。如果我从一个 pthread 调用 sched_yield(),它不会自行停止并放弃 CPU 给另一个 pthread 直到另一个 pthread 调用 sched_yield() 吗?我正在尝试使用共享一个数组的两个 pthread 来解决这个问题,其中 pthread2 读取 pthread1 插入的元素。在某些情况下,我的代码可能从 pthread2 运行ning 开始,但数组为空,我需要它通过 sched_yield() 停止并让 pthread1 填充数组。但是,pthread1 似乎没有启动并填充数组,我不确定为什么。我真的可以只调用 sched_yield() 切换到 pthread1 并从 运行ning 停止 pthread2 直到 pthread1 调用 sched_yield() 吗?

当一个线程正在调用pthread_yield()时,系统只是进入了调度器。然后,调度程序根据与操作系统相关的许多标准(调度类型、优先级、当前 CPU 处理器负载数等)决定必须执行的线程。
简而言之,你不应该使用 pthread_yield() 来同步共享数据但互斥的 2 个线程:看看 POSIX API 就像 pthread_mutex_lock().

你可以考虑使用条件变量。看看 pthread_cond_init(), pthread_cond_wait(), pthread_cond_signal()... 您正在实施所谓的“producer/consumer 问题”:多个生产者线程写入共享资源,多个消费者线程从中读取。需要同步以确保:

  • 消费者每次访问资源时都会读取一致的数据。多个 reader 可以同时读取,因为它们不修改资源;
  • 如果生产者正在修改资源,则没有消费者可以访问该资源;相反,如果至少有一个 reader 正在读取该资源,则没有作者可以访问该资源;
  • 生产者必须拥有对资源的独占访问权才能在其上写入,而不会与其他生产者交错。

这是一个实现多个线程的示例程序writing/reading 全局共享资源。生产者和消费者函数分别接收回调以写入和读取全局资源。它们都使用一个条件变量来维护一个 readers 的计数器,使多个 readers 可以同时读取资源,并确保在任何时刻只有一个写入者修改资源没有待处理的 reader。为简化源文件,未检查服务的 return 代码。

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

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef int (* write_op_t)(void *data);
typedef int (* read_op_t)(void *data);
int readers;

char resource[50];

int producer(write_op_t wr, void *data)
{
  int rc;

  pthread_mutex_lock(&mutex);

  // If there are readers ==> we wait
  while (readers > 0) {
    // Wait for a signal from the readers
    pthread_cond_wait(&cond, &mutex);
  }

  // The mutex is locked here

  // Write operation
  rc = (* wr)(data);

  // wake up any waiting writer
  pthread_cond_signal(&cond);

  pthread_mutex_unlock(&mutex);

  return rc;
}


int consumer(read_op_t rd, void *data)
{
  int rc;

  pthread_mutex_lock(&mutex);

  // One more reader
  readers ++;

  pthread_mutex_unlock(&mutex);

  // Read operation
  rc = (* rd)(data);

  pthread_mutex_lock(&mutex);

  // One less reader
  readers --;

  // Wake up any waiting writer
  if (readers == 0) {
    pthread_cond_signal(&cond);
  }

  pthread_mutex_unlock(&mutex);

}


int read_op(void *data)
{
  char *name = (char *)data;
  char local_resource[sizeof(resource) + 50];

  snprintf(local_resource, sizeof(local_resource), "readers=%d, resource='%s'", readers, resource);
  printf("%s: %s\n", name, local_resource);

  return 0;
}

int write_op(void *data)
{
  char *name = (char *)data;
  printf("%s writing\n", name);
  snprintf(resource, sizeof(resource), "%s", name);

  return 0;
}


void *entry(void *p)
{
  char *name = (char *)p;
  int i = 10;
  int rc;

  do {

    if (i & 0x1) {
      rc = producer(write_op, name);
    } else {
      rc = consumer(read_op, name);
    }

    i --;

  } while (i);

  printf("End of %s\n", name);

  return NULL;

}


int main(void)
{
  pthread_t tid[4];
  int i;
  char *name[4];

  for (i = 0; i < 4; i ++) {
    name[i] = malloc(20);
    snprintf(name[i], 20, "thread#%d", i);
    pthread_create(&(tid[i]), NULL, entry, name[i]);
  }

  for (i = 0; i < 4; i ++) {
    pthread_join(tid[i], NULL);
    free(name[i]);
  }

  return 0;
}

在Linux下是这样搭建的:

$ gcc prod_cons.c -o prod_cons -lpthread

那么,你可以运行它

$ ./prod_cons
thread#0: readers=1, resource=''
thread#1: readers=2, resource=''
thread#2: readers=2, resource=''
thread#3: readers=2, resource=''
thread#3 writing
thread#2 writing
thread#1 writing
thread#1: readers=1, resource='thread#1'
thread#1 writing
thread#1: readers=1, resource='thread#1'
thread#3: readers=1, resource='thread#1'
thread#1 writing
thread#0 writing
thread#0: readers=1, resource='thread#0'
thread#2: readers=1, resource='thread#0'
thread#1: readers=2, resource='thread#0'
thread#1 writing
thread#3 writing
thread#3: readers=1, resource='thread#3'
thread#2 writing
thread#2: readers=1, resource='thread#2'
thread#0 writing
thread#0: readers=1, resource='thread#0'
thread#0 writing
thread#0: readers=1, resource='thread#0'
thread#1: readers=1, resource='thread#0'
thread#2 writing
thread#0 writing
thread#0: readers=1, resource='thread#0'
thread#0 writing
End of thread#0
thread#1 writing
End of thread#1
thread#3 writing
thread#3: readers=1, resource='thread#3'
thread#2: readers=2, resource='thread#3'
thread#2 writing
thread#2: readers=1, resource='thread#2'
thread#2 writing
End of thread#2
thread#3 writing
thread#3: readers=1, resource='thread#3'
thread#3 writing
End of thread#3