繁体   English   中英

如何一一使用 C (sem_t) 线程

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM