在纯c中,在线程中更改数组/结构/..的部分而不阻塞整个事情

标签 c arrays multithreading thread-safety pthreads

我想在多个线程中修改数组(或结构)的一些(不是全部)字段,而不阻塞数组的其余部分,因为它的其余部分正在其他线程中修改。这是如何实现的?我找到了一些答案,但它们是针对 C++ 的,我想用 C 来做。 这是我到目前为止得到的代码:

#define _GNU_SOURCE

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#define ARRAYLENGTH 5
#define TARGET 10000

int target;

typedef struct zstr{
    int* array;
    int place;
    int run;
    pthread_mutex_t* locks;
}zstr;

void *countup(void *);

int main(int argc, char** args){
    int al;
    if(argc>2){
        al=atoi(args[1]);
        target=atoi(args[2]);
    }else{
        al=ARRAYLENGTH;
        target=TARGET;
    }
    printf("%d %d\n", al, target);
    zstr* t=malloc(sizeof(zstr));
    t->array=calloc(al, sizeof(int));
    t->locks=calloc(al, sizeof(pthread_mutex_t));
    int* rua=calloc(al, sizeof(int));
    pthread_t id[4*al];
    for(int i=0; i<al; i++)
            pthread_mutex_init(&(t->locks[i]), NULL);
    for(int j=0; j<4*al; j++){
        int st=j%al;
        t->run=rua[st]++;
        t->place=st;
        pthread_create(&id[j], NULL, &countup, t);
    }
    for(int k=0; k<4*al; k++){
        pthread_join(id[k], NULL);
    }
    for(int u=0; u<al; u++)
           printf("%d\n", t->array[u]);
    free(rua);
    free(t->locks);
    free(t->array);
    return 0;
}

void *countup(void* table){
    zstr* nu=table;
    if(!nu->run){
        pthread_mutex_lock(nu->locks + nu->place);
    }else{
        pthread_mutex_trylock(nu->locks + nu->place);
    }
    while(nu->array[nu->place]<target)
        nu->array[nu->place]++;
    pthread_mutex_unlock(nu->locks + nu->place); 
    return NULL;
}
有时这工作得很好,但随后计算出错误的值,并且对于安静的排序问题(例如默认值),它需要很长时间(奇怪的是,当我将它们作为参数传递时,它工作了一次)。

最佳答案

数组或结构的一部分没有什么特别的。重要的是正确使用应用于给定值的互斥体或其他同步。

在这种情况下,您似乎没有检查锁定函数的结果。

countup 函数的设计只允许单个线程访问该对象,在释放锁之前将值一直运行到目标,但不检查 trylock 结果。

因此,可能发生的情况是第一个线程获得锁,同一互斥锁上的后续线程调用 trylock 并未能获得锁,但代码不检查结果。然后,多个线程会在不同步的情况下递增相同的值。鉴于所有指针取消引用,索引和增量操作不能保证是原子的,从而导致值增长远远超出目标的问题。

这个故事的寓意是检查函数结果并处理错误。

关于在纯c中,在线程中更改数组/结构/..的部分而不阻塞整个事情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37557292/

相关文章:

winapi - 多线程 Win32 GUI 消息循环

c - 绘制两次相同的 Sprite 或绘制一个双倍大小的 Sprite 更好?

PHP excel - 数据循环?

JavaScript 数组验证并查找最后一项

c# - 什么限制了 C# 中的数组大小?

c# - 在控制台应用程序中同步来自不同线程的事件

multithreading - Delphi多线程写入文件: I/O error 32

c - he->h_addr_list[0] 总是默认接口(interface)吗?

c - scanf() 格式字符串中尾随空格有何影响?

c++ - 在 C++ 中循环目录结构时给定名称是文件或目录