[英]How can I use C (sem_t) threads one by one
我尝试一个一个地使用 C (sem_t) 线程但是当使用锁定时循环总是在一个线程上继续。我认为问题是只使用 2 个线程并且线程非常快,但是当我使用 10 个线程时,我看到线程参与,但仍然是 output 连续 3-4 次。
这是我的线程 function
这是我的主要 function
这是我在 ubuntu 终端上运行的电话
--------and--------
这是我的 output
这是我预期的 output
顺便说一句,代码完全按照我想要的方式工作,除了这个问题。
从我的热门评论中:
您必须配对sem_wait/sem_post
调用,否则它会阻塞。 对于计数器,请考虑改用stdatomic.h
原语。
即使没有t2
你也会有竞争条件/线程饥饿。 简化: while (1) { sem_wait(&t); do_stuff(); sem_post(&t); }
while (1) { sem_wait(&t); do_stuff(); sem_post(&t); }
假设 taskA 首先获取信号量,然后 taskB 执行sem_wait
。 当 taskA 在第 1 次迭代中执行sem_post
时,它会在第 2 次迭代中立即执行sem_wait
。那么,哪个任务继续执行? 可能是任务A。 不能保证 taskB 会得到信号量。 它可能偶尔会赢得比赛,但不是你想要的公平。
是的,你是对的,但是在“sem_wait(&t2)”之后我锁定了线程,所以其他线程无法执行某些操作,对吗? 是否有可能其他线程可以通过锁操作“sem_wait(&t2)”? ——艾伦·伯克·萨尔塔什
正如我在评论中提到的,使用信号量并不是实现共享递减迭代计数器的最佳方式。
使用atomic_fetch_add
可以干净利落地达到同样的效果。 或者,只需在锁定的关键部分内进行减量。
使用所有各种 [debug] printf
并执行fopen / fprintf / fclose
,您不会获得很好的计时结果。
也就是说,我们正在测量一个带有printf
的系统,而不是真正的系统。 因此,I/O 的暂停将掩盖线程饥饿问题。
根据您的实际应用程序,您可能需要做更多工作来实现公平性和防止线程饥饿。
这是代码的重构版本。 由于您没有发布完整的代码,我不得不综合变量定义和main
等。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdatomic.h>
sem_t t;
sem_t t2;
pthread_mutex_t mtx;
#define MAXITER 10000
#if USEATOMIC
int counter;
#else
volatile int counter;
#endif
#define MAXTASK 2
pthread_t tsklist[MAXTASK];
void *
run(void *args)
{
int val = 1;
long thridx = (long) args;
printf("Hello There! thread kthread ID - %ld\n", thridx);
#if 0
sem_getvalue(&t2, &val);
#endif
while (val > 0) {
printf("%ld: LOOPTOP val=%d\n", thridx, val);
sem_wait(&t);
pthread_mutex_lock(&mtx);
// NOTE/BUG: this will block a 2nd task forever
#if 0
sem_wait(&t2);
sem_getvalue(&t2, &val);
#endif
printf("%ld: LOCKED\n", thridx);
double r = (double) rand() / RAND_MAX * 20.0 - 10.0;
double r2 = (double) rand() / RAND_MAX * 4.0 - 2.0;
if (r < 0 && r2 < 0) {
FILE *fp = fopen("f.out", "a");
fprintf(fp, "%lf ---- %lf\n", r, r2);
fclose(fp);
}
else if (r > 0 && r2 < 0) {
FILE *fp = fopen("f2.out", "a");
fprintf(fp, "%lf ---- %lf\n", r, r2);
fclose(fp);
}
else if (r > 0 && r2 > 0) {
FILE *fp = fopen("f3.out", "a");
fprintf(fp, "%lf ---- %lf\n", r, r2);
fclose(fp);
}
else if (r < 0 && r2 > 0) {
FILE *fp = fopen("f4.out", "a");
fprintf(fp, "%lf ---- %lf\n", r, r2);
fclose(fp);
}
else {
FILE *fp = fopen("f5.out", "a");
fprintf(fp, "%lf ---- %lf\n", r, r2);
fclose(fp);
}
#if ! USEATOMIC
val = --counter;
#endif
sem_post(&t);
pthread_mutex_unlock(&mtx);
#if USEATOMIC
val = atomic_fetch_add(&counter,-1);
#endif
}
// NOTE/BUG: this aborts _all_ threads
#if 0
exit(0);
#else
return (void *) 0;
#endif
}
int
main(void)
{
sem_init(&t,0,1);
sem_init(&t2,0,1);
pthread_mutex_init(&mtx,NULL);
#if USEATOMIC
atomic_store(&counter,MAXITER);
#else
counter = MAXITER;
#endif
for (long idx = 0; idx < MAXTASK; ++idx)
pthread_create(&tsklist[idx],NULL,run,(void *) idx);
for (long idx = 0; idx < MAXTASK; ++idx)
pthread_join(tsklist[idx],NULL);
int val = atomic_load(&counter);
printf("counter=%d\n",counter);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.