我怎样才能一个一个地使用C(sem_t)线程
How can I use C (sem_t) threads one by one
我尝试一个一个地使用 C (sem_t) 线程,但是当使用锁时,循环总是在一个单一的 thread.I 上继续,我认为问题是只使用 2 个线程和线程速度很快,但是当我使用10个线程时,我看到线程参与但仍然连续输出3-4次。
这是我的线程函数
这是我的主要功能
这是我在 ubuntu 终端上给 运行 的呼叫
--------and--------
这是我的输出
这是我的预期输出
顺便说一句,除了这个问题,代码完全按照我的要求工作。
来自我的热门评论:
您必须配对 sem_wait/sem_post
调用,否则它会阻塞。对于计数器,请考虑改用 stdatomic.h
原语。
即使没有t2
,你也会有一场condition/thread饥饿的比赛。简化:while (1) { sem_wait(&t); do_stuff(); sem_post(&t); }
假设任务A先获取信号量,然后任务B获取信号量sem_wait
。当 taskA 在第 1 次迭代中执行 sem_post
时,它 立即 在第 2 次迭代中执行 sem_wait
。那么,哪个任务继续进行?可能是任务A。无法保证 taskB 将获得信号量。它可能偶尔会赢得比赛,但不是你想要的公平。
Yes you right but after "sem_wait(&t2)" I locked the thread so there is no way other thread do some operation right? Is there a possiblity that other thread can operate "sem_wait(&t2)" through lock? – Eren Berk Saltaş
正如我在评论中提到的,使用信号量不是实现共享递减迭代计数器的最佳方式。
使用atomic_fetch_add
可以干净利落地达到同样的效果。或者,在锁定的临界区内做递减。
所有各种 [调试] printf
和执行 fopen / fprintf / fclose
,你不会得到很好的计时结果。
也就是说,我们正在用 printf
和 而非 真实系统测量系统。因此,I/O 的暂停将掩盖线程饥饿问题。
根据您的实际应用程序,您可能需要做更多工作才能实现公平并防止线程饥饿。
这是代码的重构版本。由于你没有post你的完整代码,我不得不综合变量定义和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;
}
我尝试一个一个地使用 C (sem_t) 线程,但是当使用锁时,循环总是在一个单一的 thread.I 上继续,我认为问题是只使用 2 个线程和线程速度很快,但是当我使用10个线程时,我看到线程参与但仍然连续输出3-4次。
这是我的线程函数
这是我的主要功能
这是我在 ubuntu 终端上给 运行 的呼叫
--------and--------
这是我的输出
这是我的预期输出
顺便说一句,除了这个问题,代码完全按照我的要求工作。
来自我的热门评论:
您必须配对 sem_wait/sem_post
调用,否则它会阻塞。对于计数器,请考虑改用 stdatomic.h
原语。
即使没有t2
,你也会有一场condition/thread饥饿的比赛。简化:while (1) { sem_wait(&t); do_stuff(); sem_post(&t); }
假设任务A先获取信号量,然后任务B获取信号量sem_wait
。当 taskA 在第 1 次迭代中执行 sem_post
时,它 立即 在第 2 次迭代中执行 sem_wait
。那么,哪个任务继续进行?可能是任务A。无法保证 taskB 将获得信号量。它可能偶尔会赢得比赛,但不是你想要的公平。
Yes you right but after "sem_wait(&t2)" I locked the thread so there is no way other thread do some operation right? Is there a possiblity that other thread can operate "sem_wait(&t2)" through lock? – Eren Berk Saltaş
正如我在评论中提到的,使用信号量不是实现共享递减迭代计数器的最佳方式。
使用atomic_fetch_add
可以干净利落地达到同样的效果。或者,在锁定的临界区内做递减。
所有各种 [调试] printf
和执行 fopen / fprintf / fclose
,你不会得到很好的计时结果。
也就是说,我们正在用 printf
和 而非 真实系统测量系统。因此,I/O 的暂停将掩盖线程饥饿问题。
根据您的实际应用程序,您可能需要做更多工作才能实现公平并防止线程饥饿。
这是代码的重构版本。由于你没有post你的完整代码,我不得不综合变量定义和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;
}