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
我是这个概念的新手,有点困惑。假设我想 运行 在单个内核上使用两个 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