C pthread:满足条件时如何激活一个线程?
C pthread: how to activate one thread when a condition is met?
考虑以下程序:
// Compilation:
// gcc -Wall -Wextra -pedantic -Wno-unused-parameter -O3 test.c -o test -pthread
// Include
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
// Common variables
sem_t sem; // Semaphore
static const int nthr = 4; // Number of threads
static int n = 0; // Global counter
// Wait for a given number of seconds
void wait(unsigned int seconds)
{
unsigned int limit = time(NULL) + seconds;
while (time(NULL) < limit);
}
// Function f0
void* f0(void* arg)
{
while (n < 2); // Here
// Doing stuff that does no require any access to shared variable
printf("...doing stuff in f0...\n");
pthread_exit(NULL);
}
// Function fn
void* fn(void* arg)
{
sem_wait(&sem);
wait(1);
printf("entering fn: n = %d\n", n);
n++;
printf("leaving fn: n = %d\n", n);
wait(1);
sem_post(&sem);
pthread_exit(NULL);
}
// Main
int main(int argc, char* argv[])
{
pthread_t thr[nthr];
sem_init(&sem, 0, 1);
pthread_create(&thr[0], NULL, f0, NULL);
for (int i = 1; i < nthr; ++i) pthread_create(&(thr[i]), NULL, fn, NULL);
for (int i = 0; i < nthr; ++i) pthread_join(thr[i], NULL);
return 0;
}
该程序执行以下操作:
thread0
执行 f0
而其他线程正在执行 fn
。我希望 f0
等到两个线程递增 n
后再做某事。
当前标记为 Here
的行应该这样做,但它不起作用。如何正确地做到这一点(尽可能使用信号量而不是互斥量)?
你可以使用一个pthread_cond,如评论中所述:
https://linux.die.net/man/3/pthread_cond_init
IMO cond 有点复杂,所以如果你刚开始接触多线程世界,我建议首先使用 mutex_lock:
http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_lock.html
在这种情况下,你应该使用两把锁,一把用于f0函数(f0_lock),另一把用于读/写"n"(var_n_lock)多变的。您的程序应该:
- 从 f0_lock 锁定和 var_n_lock 解锁开始。
- f0 将等待 f0_lock。
- fn 线程将做他们需要做的事情,然后锁定 var_n_lock,将 n 增加 1 并检查是否 n == 2,如果是则解锁 f0_lock 最后,解锁 var_n_lock.
- 当 n == 2 并且线程 运行 f0 将被解锁并保持 运行.
我注意到几件事:在我看来,fn 线程将在 f0 之前完成,如果是这种情况,您应该颠倒连接的顺序,这将导致一个小的优化。另外,如果你想让你的程序等待一段时间,使用 sleep 或 usleep,它会为你节省很多 CPU.
希望对您有所帮助。
考虑以下程序:
// Compilation:
// gcc -Wall -Wextra -pedantic -Wno-unused-parameter -O3 test.c -o test -pthread
// Include
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
// Common variables
sem_t sem; // Semaphore
static const int nthr = 4; // Number of threads
static int n = 0; // Global counter
// Wait for a given number of seconds
void wait(unsigned int seconds)
{
unsigned int limit = time(NULL) + seconds;
while (time(NULL) < limit);
}
// Function f0
void* f0(void* arg)
{
while (n < 2); // Here
// Doing stuff that does no require any access to shared variable
printf("...doing stuff in f0...\n");
pthread_exit(NULL);
}
// Function fn
void* fn(void* arg)
{
sem_wait(&sem);
wait(1);
printf("entering fn: n = %d\n", n);
n++;
printf("leaving fn: n = %d\n", n);
wait(1);
sem_post(&sem);
pthread_exit(NULL);
}
// Main
int main(int argc, char* argv[])
{
pthread_t thr[nthr];
sem_init(&sem, 0, 1);
pthread_create(&thr[0], NULL, f0, NULL);
for (int i = 1; i < nthr; ++i) pthread_create(&(thr[i]), NULL, fn, NULL);
for (int i = 0; i < nthr; ++i) pthread_join(thr[i], NULL);
return 0;
}
该程序执行以下操作:
thread0
执行 f0
而其他线程正在执行 fn
。我希望 f0
等到两个线程递增 n
后再做某事。
当前标记为 Here
的行应该这样做,但它不起作用。如何正确地做到这一点(尽可能使用信号量而不是互斥量)?
你可以使用一个pthread_cond,如评论中所述:
https://linux.die.net/man/3/pthread_cond_init
IMO cond 有点复杂,所以如果你刚开始接触多线程世界,我建议首先使用 mutex_lock:
http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_lock.html
在这种情况下,你应该使用两把锁,一把用于f0函数(f0_lock),另一把用于读/写"n"(var_n_lock)多变的。您的程序应该:
- 从 f0_lock 锁定和 var_n_lock 解锁开始。
- f0 将等待 f0_lock。
- fn 线程将做他们需要做的事情,然后锁定 var_n_lock,将 n 增加 1 并检查是否 n == 2,如果是则解锁 f0_lock 最后,解锁 var_n_lock.
- 当 n == 2 并且线程 运行 f0 将被解锁并保持 运行.
我注意到几件事:在我看来,fn 线程将在 f0 之前完成,如果是这种情况,您应该颠倒连接的顺序,这将导致一个小的优化。另外,如果你想让你的程序等待一段时间,使用 sleep 或 usleep,它会为你节省很多 CPU.
希望对您有所帮助。