我试图一个接一个地使用C(sem_t(线程,但当使用锁时,循环总是在单个线程上继续。我认为问题是只使用2个线程,而且线程非常快,但当我使用10个线程时,我看到线程参与其中,但仍然连续输出3-4次。
这是我的线程函数
这是我的主要功能
这是我在ubuntu终端上运行的电话
--------and--------
这是我的输出
这是我的预期输出
顺便说一句,除了这个问题,代码的工作方式完全符合我的要求。
来自我的热门评论:
您必须将sem_wait/sem_post
调用配对,否则它将被阻止。对于计数器,请考虑使用stdatomic.h
基元。
即使没有t2
,也会出现竞争条件/线程不足。简化:while (1) { sem_wait(&t); do_stuff(); sem_post(&t); }
假设taskA首先获得信号量,然后taskB执行sem_wait
。当taskA在迭代1中执行sem_post
时,它会立即在迭代2中执行sem_wait
。那么,接下来是哪项任务?可能是任务A。不能保证taskB会得到信号量。它可能偶尔会赢得比赛,但不是你想要的公平。
是的,你现在但在";等待(&t2(";我锁定了线程,所以其他线程无法执行某些操作,对吗?是否存在其他线程可以操作的可能性;等待(&t2(";通过锁?-Eren Berk Saltaş
正如我在评论中提到的,使用信号量不是实现共享递减迭代计数器的最佳方式。
使用atomic_fetch_add
可以干净地达到同样的效果。或者,只在锁定的临界段内进行递减。
使用各种[调试]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 - %ldn", thridx);
#if 0
sem_getvalue(&t2, &val);
#endif
while (val > 0) {
printf("%ld: LOOPTOP val=%dn", 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: LOCKEDn", 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 ---- %lfn", r, r2);
fclose(fp);
}
else if (r > 0 && r2 < 0) {
FILE *fp = fopen("f2.out", "a");
fprintf(fp, "%lf ---- %lfn", r, r2);
fclose(fp);
}
else if (r > 0 && r2 > 0) {
FILE *fp = fopen("f3.out", "a");
fprintf(fp, "%lf ---- %lfn", r, r2);
fclose(fp);
}
else if (r < 0 && r2 > 0) {
FILE *fp = fopen("f4.out", "a");
fprintf(fp, "%lf ---- %lfn", r, r2);
fclose(fp);
}
else {
FILE *fp = fopen("f5.out", "a");
fprintf(fp, "%lf ---- %lfn", 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=%dn",counter);
return 0;
}