自旋锁函数的使用

Posted

技术标签:

【中文标题】自旋锁函数的使用【英文标题】:Usage of spinlock functions 【发布时间】:2015-04-29 21:21:28 【问题描述】:

如何使用这些功能? 我已全局声明锁定。

pthread_spinlock_t lock;

自旋锁也在本地初始化。

pthread_spin_init(&lock, 1); // non-zero as pshared for IPC

但现在我想锁定我的关键整数并增加它。 我有多个进程循环运行:

while(0 != pthread_spin_trylock(&lock));
criticalInt += 1;
pthread_spin_unlock(&lock);

为什么这不起作用? 还有,下面这个函数是怎么用的?

pthread_spin_lock(&lock);

编辑:

for (i=0; i < NUM_CHILDREN; i++) 

   pid[i] = fork();
   if (pid[i] == -1)  return EXIT_FAILURE; 
   if (pid[i] == 0) 
   while (criticalInt < MAXCOUNT) 
      pthread_spin_lock(&lock);
      criticalInt += 1;
      pthread_spin_unlock(&lock);
      count++;
   
   printf("Process %i counted %i\n", i, count);


对于 1000000 的 MAXCOUNT,帽子会产生以下输出:

    Process 3 counted 687858
    Process 0 counted 815657
    Process 1 counted 640191
    Process 2 counted 744340

实际上加起来应该是1000000。但他们不是。

如果我完全删除锁,我会得到类似的结果。

【问题讨论】:

你能准确描述一下是什么行为让你说它不起作用吗?您收到错误消息吗?你的程序挂了吗?它会产生意外的输出吗? 非常抱歉,我忘记了循环。好吧,它根本不会锁定我的应用程序。信号量就像一个魅力,但不是这个自旋锁。 什么——你自己在纺纱?只需使用 pthread_spin_lock 而不是那个循环。您的代码的预编辑形式是正确的。 另外,什么行为让你说它“根本不锁定我的应用程序”? pthread_spin_lock 在获得锁之前不会返回。看起来这就是您试图通过循环 trylock 来实现的目标。 【参考方案1】:

要使 POSIX 线程的任何典型用法正常工作,您需要使用 pthread_create() 来启动一个新线程。在这里,您使用的是fork(),它启动了一个与父进程不同的地址空间的新进程。

更新:@Ramiz 在 cmets 中指出,一些 pthread 原语可以利用共享内存区域,从而允许它们跨分叉进程进行操作。这不是使用 pthread 东西的常用方法,但它是可能的!

【讨论】:

criticalInt 实际上是共享内存。 共享内存中是否也“锁定”了? 不,我怎么把它弄进去? 如果您查看 pthread_spinlock_t 的 typedef,它只是“volatile int”。如果您可以像声明 criticalInt 一样声明锁,它可能会起作用。 这个答案完全正确:您可以在分叉的进程上使用 pthread_spin_lock,但他们必须有权访问锁,例如通过共享内存和 pthread_spin_init 必须使用标志 PTHREAD_PROCESS_SHARED 完成,请参阅man7.org/linux/man-pages/man3/pthread_spin_init.3.html 但是,不建议推荐这种方法。【参考方案2】:

如果您希望自旋锁被多个进程而不是线程使用,那么自旋锁本身也需要在共享进程内存中生成。 PTHREAD_PROCESS_SHARED 的 pshared 值本身不足以在进程之间共享自旋锁。

【讨论】:

以上是关于自旋锁函数的使用的主要内容,如果未能解决你的问题,请参考以下文章

Linux 并发与竞争(原子操作自旋锁信号量互斥体)

内核同步机制

信号量,互斥锁,自旋锁

Linux驱动之并发与竞争

自旋锁

使用编译器内在函数实现自旋锁以同步 OpenMP 线程