首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Futex和p螺纹问题

Futex和p螺纹问题
EN

Stack Overflow用户
提问于 2022-07-16 06:55:15
回答 1查看 150关注 0票数 1

我在用线程测试futexes。我写了以下程序:

代码语言:javascript
复制
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
#include <stdatomic.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

int64_t sum;
pthread_mutex_t mtx;

uint32_t ftx;

int futex(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3)
{
    return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
}

void fwait(uint32_t *futx)
{
    long st;
    uint32_t one = 1;
    
    do {
        if (atomic_compare_exchange_strong(futx, &one, 0))
            break;
        
        st = futex(futx, FUTEX_WAIT_PRIVATE, 0, NULL, NULL, 0);
        
        if ((st == -1) && (errno != EAGAIN)) {
            printf("error-wait-futex\n");
            exit(1);
        }
    } while (1);
    
}

void fwake(uint32_t *futx)
{
    long st;
    uint32_t zero = 0;
    
    if (atomic_compare_exchange_strong(futx, &zero, 1)) {
        st = futex(futx, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
        if (st == -1) {
            printf("error-wake-futex\n");
            exit(1);
        }
    }
}

void lock(void)
{
    fwait(&ftx);
}

void unlock(void)
{
    fwake(&ftx);
}

void * t1_handler(void *arg)
{
    int mod;
    uint64_t x;
    
    mod = *(int *)arg;
    
    x = 0;
    while (x < 1000000) {
        lock();
        sum += mod;
        x++;
        unlock();
    }
}

void proc(void)
{
    pthread_t t1, t2;
    int a1, a2;
    
    sum = 0;
    ftx = 1;
    
    a1 = 1;
    a2 = -1;
    
    pthread_mutex_init(&mtx, NULL);
    pthread_create(&t1, NULL, t1_handler, &a1);
    pthread_create(&t2, NULL, t1_handler, &a2);
    
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("sum: %lld\n", sum);
}

int main(void)
{
    proc();
    return 0;
}

有时它以和的形式返回0,这是适当的值,但有时和的返回值与0不同。

我的问题是,为什么“和”的返回值与0不同?我怀疑锁是有什么问题,但目前我不知道是什么。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-21 20:20:07

实现的问题在于使用atomic_compare_exchange_strong()的方式。请注意,在C参考中:

如果比较失败,则将obj指向的内存的实际内容加载到预期的*中(执行加载操作)。

在您的代码中,这意味着当这个原子操作失败(即futx不是1)时,futx的值将在one加载,这意味着现在的one值是0。

从现在开始,锁函数将中断,这使得原子操作将成功(即futx具有与one相同的值,即0),即使在锁定时也是如此,这意味着我们可以有多个线程同时持有它。要解决这个问题,您需要重置每个循环的one

代码语言:javascript
复制
do {
    uint32_t one = 1;
    if (atomic_compare_exchange_strong(futx, &one, 0))
        break;
    
    ...
} while (1);

或者更好的是,始终将锁设置为接受,并检查前面的值是否是空闲锁的值:

代码语言:javascript
复制
if (atomic_exchange(futx, 0) == 1)  

如果您对futexes值使用了定义,那么理解就更容易了。就你而言:

代码语言:javascript
复制
#define LOCK_FREE 1
#define LOCK_TAKEN 0
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73002167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档