在 C 中使用信号量控制线程顺序

Posted

技术标签:

【中文标题】在 C 中使用信号量控制线程顺序【英文标题】:Controlling thread order using semaphores in C 【发布时间】:2017-04-29 20:44:35 【问题描述】:

我是 C 新手,我只是想运行 Pacheco 的书“并行编程简介”中的这段代码。而且我只是不知道应该如何在main() 中实现信号量初始化。 &semaphores[dest]&semaphores[my_rank] 是数组吗?

C 代码:

/* messages is allocated and initialized to NULL in main */
/* semaphores is allocated and initialized to 0 (locked) in main */
void *Send_msg(void* rank) 
    long my_rank = (long) rank;
    long dest = (my_rank + 1) % thread_count;
    char* my_msg = (char*)malloc(MSG_MAX*sizeof(char));

    sprintf(my_msg, "Hello to %ld from %ld", dest, my_rank);
    messages[dest] = my_msg;
    sem_post(&semaphores[dest])
    /* ‘‘Unlock’’ the semaphore of dest */

    sem_wait(&semaphores[my_rank]);/* Wait for our semaphore to be unlocked */
    printf("Thread %ld > %s\n", my_rank, messages[my_rank]);

    return NULL;
 /* Send_msg */

当我试图将输出数组写入文件时,我想实现这种类型的排序机制。这是我的代码:

int k = 0;
long dest = (my_rank + 1) % THREAD_COUNT;

if(genCount%50==0)
//incrementing file name

//semapthore lock
sem_post(&semaphores[dest]);

sem_wait(&semaphores[my_rank]);

snprintf(buffer, sizeof(char) * 32, "file%i.dat", k);

//open the file
fp = fopen(buffer, "r+");
if (fp == NULL) 
  printf("I couldn't open file for writing.\n");
  exit(0);


int loop1, loop2;

//outputting the array into the file
for (loop1 = my_first_i; loop1 < my_last_i; loop1++)
  for(loop2 = my_first_i; loop2 < my_last_i; loop2++)
fprintf(fp,"%d\t", map[loop1][loop2]);
  


//close the file
fclose(fp);

k++;

main()中信号量的初始化:

  int semCount;
  for(semCount = 0; semCount < THREAD_COUNT; semCount++)
   sem_init(&semaphores[semCount], 0, 1);
  

我也有它作为一个全局变量:

#define THREAD_COUNT 4
sem_t semaphores[THREAD_COUNT];

程序编译,但它给了我这个错误:

      *** Error in `./ebola_serial': double free or corruption (out): 0x00007f49700008c0 ***
  *** Error in `======= Backtrace: =========
  /lib64/libc.so.6(+0x7238e)[0x7f49868f038e]
  ./ebola_serial/lib64/libc.so.6(+0x7a0c8)[0x7f49868f80c8]
  ': /lib64/libc.so.6(cfree+0x48)[0x7f49868fb798]
  double free or corruption (out)/lib64/libc.so.6(fclose+0x113)[0x7f49868e6473]
  ./ebola_serial[0x401717]
  /lib64/libpthread.so.0(+0x75bd)[0x7f4986c395bd]
  : 0x/lib64/libc.so.6(clone+0x6d)[0x7f498697562d]
  ======= Memory map: ========
  00007f49700008c000400000-00402000 r-xp 00000000 08:01 802698                             /home/name/Desktop/try ca/ebola_serial
  00601000-00602000 r--p 00001000 08:01 802698                             /home/name/Desktop/try ca/ebola_serial
  00602000-00603000 rw-p 00002000 08:01 802698                             /home/name/Desktop/try ca/ebola_serial
  00603000-009d3000 rw-p 00000000 00:00 0 
  01b96000-01bb7000 rw-p 00000000 00:00 0                                  [heap]
  7f4970000000-7f4970021000 rw-p 00000000 00:00 0 
  7f4970021000-7f4974000000 ---p 00000000 00:00 0 
  7f4978000000-7f4978021000 rw-p 00000000 00:00 0 
  7f4978021000-7f497c000000 ---p 00000000 00:00 0 
  7f497c000000-7f497c021000 rw-p 00000000 00:00 0 
  7f497c021000-7f4980000000 ---p 00000000 00:00 0 
  7f4980000000-7f4980021000 rw-p 00000000 00:00 0 
  7f4980021000-7f4984000000 ---p 00000000 00:00 0 
  7f4984663000-7f4984679000 r-xp 00000000 08:01 131531                     /usr/lib64/libgcc_s-4.9.2.so.1
  7f4984679000-7f4984878000 ---p 00016000 08:01 131531                     /usr/lib64/libgcc_s-4.9.2.so.1
  7f4984878000-7f4984879000 r--p 00015000 08:01 131531                     /usr/lib64/libgcc_s-4.9.2.so.1
  7f4984879000-7f498487a000 rw-p 00016000 08:01 131531                     /usr/lib64/libgcc_s-4.9.2.so.1
  7f498487a000-7f498487b000 ---p 00000000 00:00 0 
  7f498487b000-7f498507b000 rw-p 00000000 00:00 0                          [stack:7376]
  7f498507b000-7f498507c000 ---p 00000000 00:00 0 
  7f498507c000-7f498587c000 rw-p 00000000 00:00 0 
  7f498587c000-7f498587d000 ---p 00000000 00:00 0 
  7f498587d000-7f498607d000 rw-p 00000000 00:00 0                          [stack:7374]
  7f498607d000-7f498607e000 ---p 00000000 00:00 0 
  7f498607e000-7f498687e000 rw-p 00000000 00:00 0                          [stack:7373]
  7f498687e000-7f4986a28000 r-xp 00000000 08:01 130947                     /usr/lib64/libc-2.20.so
  7f4986a28000-7f4986c28000 ---p 001aa000 08:01 130947                     /usr/lib64/libc-2.20.so
  7f4986c28000-7f4986c2c000 r--p 001aa000 08:01 130947                     /usr/lib64/libc-2.20.so
  7f4986c2c000-7f4986c2e000 rw-p 001ae000 08:01 130947                     /usr/lib64/libc-2.20.so
  7f4986c2e000-7f4986c32000 rw-p 00000000 00:00 0 
  7f4986c32000-7f4986c49000 r-xp 00000000 08:01 130973                     /usr/lib64/libpthread-2.20.so
  7f4986c49000-7f4986e48000 ---p 00017000 08:01 130973                     /usr/lib64/libpthread-2.20.so
  7f4986e48000-7f4986e49000 r--p 00016000 08:01 130973                     /usr/lib64/libpthread-2.20.so
  7f4986e49000-7f4986e4a000 rw-p 00017000 08:01 130973                     /usr/lib64/libpthread-2.20.so
  7f4986e4a000-7f4986e4e000 rw-p 00000000 00:00 0 
  7f4986e4e000-7f4986f53000 r-xp 00000000 08:01 130955                     /usr/lib64/libm-2.20.so
  7f4986f53000-7f4987152000 ---p 00105000 08:01 130955                     /usr/lib64/libm-2.20.so
  7f4987152000-7f4987153000 r--p 00104000 08:01 130955                     /usr/lib64/libm-2.20.so
  7f4987153000-7f4987154000 rw-p 00105000 08:01 130955                     /usr/lib64/libm-2.20.so
  7f4987154000-7f4987174000 r-xp 00000000 08:01 130940                     /usr/lib64/ld-2.20.so
  7f4987353000-7f4987356000 rw-p 00000000 00:00 0 
  7f498736d000-7f4987373000 rw-p 00000000 00:00 0 
  7f4987373000-7f4987374000 r--p 0001f000 08:01 130940                     /usr/lib64/ld-2.20.so
  7f4987374000-7f4987376000 rw-p 00020000 08:01 130940                     /usr/lib64/ld-2.20.so
  7ffce31e3000-7ffce3205000 rw-p 00000000 00:00 0                          [stack]
  7ffce320d000-7ffce320f000 r--p 00000000 00:00 0                          [vvar]
  7ffce320f000-7ffce3211000 r-xp 00000000 00:00 0                          [vdso]
  ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
  Aborted

任何帮助将不胜感激。

【问题讨论】:

阅读man sem_init并进一步询问。 那是什么C?似乎// 变成/_ 不见了......无论如何[] 是数组下标运算符,回答你的问题。 这是来自某些电子书或扫描件的错误副本。你注意到解锁引号了吗?这些是打印引号而不是等宽字体的代码引号。下划线不见了。 OCR 的实现失败。 @Shiv 是的,抱歉没有发现。现在修好了。我试过sem_init(&amp;semaphores, 1, 0);,但没用。 您应该edit您的问题以添加其他信息,而不仅仅是使用评论。 【参考方案1】:

看起来像这样定义的信号量

sem_t semaphores[N];

其中 N 是信号量的数量

要初始化信号量,您应该使用 sem_init 函数,该函数接受一个指向所需信号量的指针,一个启用共享进程使用的标志和信号量的初始值。

sem_init(&semaphores[0], 0, 1);

在您的情况下,信号量实例存储在称为信号量的数组中,因此您必须迭代数组的所有成员以进行初始化

int i;
for(i=0;i<N;i++)
    sem_init(&semaphores[i], 0, 1);

使用信号量的 Finlay 必须以这种方式调用 sem_wait 和 sem_post 函数

sem_wait(&semaphores[0 to N-1]); // Locking semaphore
sem_post(&semaphores[0 to N-1]); // Unlocking it

【讨论】:

哦,好吧,我明白你的意思了。那么这是否意味着我应该为每个线程设置一个信号量? 信号量用于保护关键部分的数据,例如考虑生产者-消费者问题,一个线程正在生产一些数据而消费者线程正在消费它们,现在考虑两个线程正在访问相同的变量或同一时间段数据!它可能会破坏一致性或令人不安的生产者-消费者操作 因此您必须保护数据,例如使用信号量。您可以在访问关键部分(两个线程之间的共享数据)之前放置信号量锁,并在完成使用它们后解锁。当信号量被锁定时,不会放置其他锁。实际上,第一个 locker 线程将继续工作,第二个和其他 locker 线程将阻塞,直到第一个 locker 线程完成它的工作并解锁信号量。请注意,两个线程必须锁定同一个信号量。 谢谢。这解释了很多。我已经实施了您的解决方案。它可以编译,但是在访问数据时给了我一个错误。我已经用错误更新了我的问题。 错误与代码无关,请在此处输入完整代码或提出新问题。该错误是关于尝试释放之前释放的 malloc'ed 区域(尝试释放一个区域两次)

以上是关于在 C 中使用信号量控制线程顺序的主要内容,如果未能解决你的问题,请参考以下文章

java多线程笔记--顺序执行

C中线程信号控制

C中线程信号控制

操作系统(二 )| 进程(概念特征状态进程控制进程同步机制信号量应用同步机制遵循规则程序执行特点线程引入目的与进程的区别)

算法学习

[C++多线程]1.3-多线程控制的另一种姿势-条件变量(condition_variable), 信号量(semaphore)