【问题标题】:thread local storage of a function函数的线程本地存储
【发布时间】:2013-12-03 14:43:56
【问题描述】:

我正在开发一个需要在多线程环境中执行队列操作的程序。 我不确定函数的线程本地存储,而不仅仅是全局变量 我试过了

__thread int head,tail;
__thread int q[MAX_NODES+2];

__thread void enqueue (int x) {
   q[tail] = x;
   tail++;
   color[x] = GRAY;
  }

__thread int dequeue () {
   int x = q[head];
   head++;
   color[x] = BLACK;
   return x;
   }

我收到以下错误

fordp.c:71: error: function definition declared '__thread'

fordp.c:77: error: function definition declared '__thread'

我在某处读到一个函数已经是线程安全的,除非它使用共享变量,所以我尝试了

__thread int head,tail;
__thread int q[MAX_NODES+2];

void enqueue (int x) {
   q[tail] = x;
   tail++;
   color[x] = GRAY;
   }

 int dequeue () {
   int x = q[head];
   head++;
   color[x] = BLACK;
   return x;
   } 

它确实编译没有错误,但是我的执行结果是错误的提示队列在多线程平台上不能很好地工作。

谁能解释一下这里发生了什么?

感谢任何帮助。

【问题讨论】:

    标签: c multithreading pthreads queue


    【解决方案1】:

    __thread 建议编译器为 每个 线程创建一个变量实例。

    我怀疑这就是你想要的队列,它是线程应该并发操作的头部和尾部,因为一个线程所做的修改将被任何人看到其他线程。

    所以不要在这里使用__thread,而是保护对全局变量的并发访问,例如使用一个或多个互斥锁。


    供您参考:http://en.wikipedia.org/wiki/Thread-local_storage

    【讨论】:

    • 感谢您的回复。实际上在我的程序中,不同线程中的队列将完成不同部分的工作。因此,由于他们将要做的工作是独立的(我猜我不需要互斥锁),我想为每个线程创建一个变量的实例,以便一个线程的变量(例如头、尾)不会与变量混淆(多线程操作期间另一个线程的头,尾)。
    • 是的,每个线程都有一个队列实例,这些队列彼此独立。实际上对于 2 个固定线程,我会将两个单独的队列定义为 q1 和 q2。问题是当我必须为 n 个线程编写程序时。那是当我不想在程序本身中将队列单独定义为 q1,q2,q3.... 时,我想定义一次队列并利用线程本地存储来在多个线程中解决它。我说得有道理吗!!!
    • @AbinashAdhikari:是的,您描述的要求和方法绝对有意义。但是,您应该将此信息添加到您的问题中,以避免进一步的误解。
    【解决方案2】:

    我认为你以错误的方式解决问题。

    您的问题是您希望将 Queue 对象与函数调用相关联(例如 enqueue)。

    在 C 中,这些对象通常称为上下文。

    您所做的是全局变量的变体。使用每线程本地存储对于暂存空间或实际每线程资源很有用。但事实并非如此。

    拥有线程安全和正确性的唯一选择是将上下文添加到函数调用中。 我删除了对color 的引用以简化操作。

    struct queue {
        unsigned head, tail;
        int q[MAX_NODES+2];
    };
    
    void enqueue (struct queue* q, int x) {
        q->q[q->tail++] = x;
    }
    
    int dequeue (struct queue* q) {
        int x = q->q[q->head++];
        return x;
    } 
    

    注意:您应该检查指针和索引。

    【讨论】:

    • 至少有一句话提到“线程本地存储”会很适合你的回答^H^H^H^H^H^Hproposal。
    • 无需重复你的答案 + cmets。在这种情况下,只是错误的工作工具。
    • 感谢您的回复。请让我问一个问题。假设我使用不同的线程执行作业的不同部分(需要队列、入队和出队)。我担心的是上述代码的 queue* q 。由于线程正在执行不同的工作,我希望他们只处理他们自己的队列副本。我担心的是使用另一个线程的队列使一个线程入队和出队。上面的代码有这个风险吗??
    • 上面的代码是可重入的——将在多个线程上工作,每个线程在不同的队列结构/对象上工作。如果您想要线程安全(单个队列上的许多线程),您需要使用某种锁(临界区或互斥锁)。互斥体将成为队列结构的一部分。一些互斥锁具有自旋锁。这意味着锁定将首先尝试 X 次以在没有上下文切换的情况下获得锁定(等待互斥锁会导致上下文切换)。所以如果锁被解锁或者如果函数存在很快,那么性能会非常好。
    • 有无锁队列之类的东西,但它们有局限性,在大多数情况下不值得努力。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多