我怎样才能一个一个地使用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;
}