首页 \ 问答 \ pthreads +信号量,为什么这不正确执行?(pthreads + semaphores, why is this not executing properly?)

pthreads +信号量,为什么这不正确执行?(pthreads + semaphores, why is this not executing properly?)

这是我正在处理的任务。 它必须使用信号量,而不是互斥量。

#include <stdio.h> 
#include <pthread.h> 
#include <assert.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <fcntl.h>
sem_t *ab, *ac, *ad, *de, *ce, *bf, *ef; 

void *a(void *arg) {
    printf("Entering A...\n");
    sleep(1);
    printf("Exiting A...\n");
    assert(sem_post(ab)==0);
    assert(sem_post(ac)==0);
    assert(sem_post(ad)==0);
    pthread_exit((void *)99);
}

void *b(void *arg) {
    assert(sem_wait(ab)==0);
    printf("Entering B...\n");
    sleep(1);
    printf("Exiting B...\n");
    assert(sem_post(bf)==0);
    pthread_exit((void *)99);
}

void *c(void *arg) {
    assert(sem_wait(ac)==0);
    printf("Entering C...\n");
    sleep(1);
    printf("Exiting C...\n");
    assert(sem_post(ce)==0);
    pthread_exit((void *)99);
}

void *d(void *arg) {
    assert(sem_wait(ad)==0);
    printf("Entering D...\n");
    sleep(1);
    printf("Exiting D...\n");
    assert(sem_post(de)==0);
    pthread_exit((void *)99);
}

void *e(void *arg) {
    assert(sem_wait(ce)==0);
    assert(sem_wait(de)==0);
    printf("Entering E...\n");
    sleep(1);
    printf("Exiting E...\n");
    assert(sem_post(ef)==0);
    pthread_exit((void *)99);
}

void *f(void *arg) {
    assert(sem_wait(bf)==0);
    assert(sem_wait(ef)==0);
    printf("Entering F...\n");
    sleep(1);
    printf("Exiting F...\n");
    pthread_exit((void *)99);
}


int main() { 
    pthread_t _a, _b, _c, _d, _e, _f;
    int r1, r2, r3, r4, r5, r6;

    ab=sem_open("foobar", O_CREAT, 0700, 0);
    ac=sem_open("foobar", O_CREAT, 0700, 0);
    ad=sem_open("foobar", O_CREAT, 0700, 0);
    ce=sem_open("foobar", O_CREAT, 0700, 0);
    de=sem_open("foobar", O_CREAT, 0700, 0);
    ef=sem_open("foobar", O_CREAT, 0700, 0);
    bf=sem_open("foobar", O_CREAT, 0700, 0);

    /*sem_init(ab,0,1);
    sem_init(ac,0,1);
    sem_init(ad,0,1);
    sem_init(ce,0,1);
    sem_init(de,0,1);
    sem_init(ef,0,1);
    sem_init(bf,0,1);*/

    assert(pthread_create(&_a, NULL, a, &r1) == 0);
    assert(pthread_create(&_b, NULL, b, &r2) == 0);
    assert(pthread_create(&_c, NULL, c, &r3) == 0);
    assert(pthread_create(&_d, NULL, d, &r4) == 0);
    assert(pthread_create(&_e, NULL, e, &r5) == 0);
    assert(pthread_create(&_f, NULL, f, &r6) == 0);

    assert(pthread_join(_a, NULL) == 0);
    assert(pthread_join(_b, NULL) == 0);
    assert(pthread_join(_c, NULL) == 0);    
    assert(pthread_join(_d, NULL) == 0);
    assert(pthread_join(_e, NULL) == 0);
    assert(pthread_join(_f, NULL) == 0);

    assert( sem_close(ab)==0 ); 
    assert( sem_close(ac)==0 ); 
    assert( sem_close(ad)==0 ); 
    assert( sem_close(ce)==0 );
    assert( sem_close(de)==0 ); 
    assert( sem_close(bf)==0 );
    assert( sem_close(ef)==0 ); 

    return 0; 
}

这很简单,但由于某种原因,它没有按照正确的顺序执行。 输出很不一致,但始终不正确。 以下是一个示例输出:

输入A ...
输入B ... <---- sem_post(ab)还没有被调用
退出A ...
输入C ...
输入D ...
退出B ...
退出D ...
退出C ...
进入E ...
输入F ...
正在退出F ...
退出E ...

它应该遵循以下图表:

任何与此有关的帮助都将不胜感激,但这是一项任务,所以不要开始告诉我以完全不同的方式来完成,并且不要直接给出答案,只需指出正确的方向即可。


This is an assignment I'm working on. It must use semaphores, not mutex.

#include <stdio.h> 
#include <pthread.h> 
#include <assert.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <fcntl.h>
sem_t *ab, *ac, *ad, *de, *ce, *bf, *ef; 

void *a(void *arg) {
    printf("Entering A...\n");
    sleep(1);
    printf("Exiting A...\n");
    assert(sem_post(ab)==0);
    assert(sem_post(ac)==0);
    assert(sem_post(ad)==0);
    pthread_exit((void *)99);
}

void *b(void *arg) {
    assert(sem_wait(ab)==0);
    printf("Entering B...\n");
    sleep(1);
    printf("Exiting B...\n");
    assert(sem_post(bf)==0);
    pthread_exit((void *)99);
}

void *c(void *arg) {
    assert(sem_wait(ac)==0);
    printf("Entering C...\n");
    sleep(1);
    printf("Exiting C...\n");
    assert(sem_post(ce)==0);
    pthread_exit((void *)99);
}

void *d(void *arg) {
    assert(sem_wait(ad)==0);
    printf("Entering D...\n");
    sleep(1);
    printf("Exiting D...\n");
    assert(sem_post(de)==0);
    pthread_exit((void *)99);
}

void *e(void *arg) {
    assert(sem_wait(ce)==0);
    assert(sem_wait(de)==0);
    printf("Entering E...\n");
    sleep(1);
    printf("Exiting E...\n");
    assert(sem_post(ef)==0);
    pthread_exit((void *)99);
}

void *f(void *arg) {
    assert(sem_wait(bf)==0);
    assert(sem_wait(ef)==0);
    printf("Entering F...\n");
    sleep(1);
    printf("Exiting F...\n");
    pthread_exit((void *)99);
}


int main() { 
    pthread_t _a, _b, _c, _d, _e, _f;
    int r1, r2, r3, r4, r5, r6;

    ab=sem_open("foobar", O_CREAT, 0700, 0);
    ac=sem_open("foobar", O_CREAT, 0700, 0);
    ad=sem_open("foobar", O_CREAT, 0700, 0);
    ce=sem_open("foobar", O_CREAT, 0700, 0);
    de=sem_open("foobar", O_CREAT, 0700, 0);
    ef=sem_open("foobar", O_CREAT, 0700, 0);
    bf=sem_open("foobar", O_CREAT, 0700, 0);

    /*sem_init(ab,0,1);
    sem_init(ac,0,1);
    sem_init(ad,0,1);
    sem_init(ce,0,1);
    sem_init(de,0,1);
    sem_init(ef,0,1);
    sem_init(bf,0,1);*/

    assert(pthread_create(&_a, NULL, a, &r1) == 0);
    assert(pthread_create(&_b, NULL, b, &r2) == 0);
    assert(pthread_create(&_c, NULL, c, &r3) == 0);
    assert(pthread_create(&_d, NULL, d, &r4) == 0);
    assert(pthread_create(&_e, NULL, e, &r5) == 0);
    assert(pthread_create(&_f, NULL, f, &r6) == 0);

    assert(pthread_join(_a, NULL) == 0);
    assert(pthread_join(_b, NULL) == 0);
    assert(pthread_join(_c, NULL) == 0);    
    assert(pthread_join(_d, NULL) == 0);
    assert(pthread_join(_e, NULL) == 0);
    assert(pthread_join(_f, NULL) == 0);

    assert( sem_close(ab)==0 ); 
    assert( sem_close(ac)==0 ); 
    assert( sem_close(ad)==0 ); 
    assert( sem_close(ce)==0 );
    assert( sem_close(de)==0 ); 
    assert( sem_close(bf)==0 );
    assert( sem_close(ef)==0 ); 

    return 0; 
}

It's pretty simple but for some reason it's not executing in the right order. The output is far from consistent but always incorrect. Here is one sample output:

Entering A...
Entering B... <----sem_post(ab) has not even been called yet
Exiting A...
Entering C...
Entering D...
Exiting B...
Exiting D...
Exiting C...
Entering E...
Entering F...
Exiting F...
Exiting E...

It should be following this diagram:

Any help with this will be greatly appreciated, but it's an assignment so don't start telling me to do it a completely different way and don't give the answer straight up, just point me in the right direction.


原文:https://stackoverflow.com/questions/6405189
更新时间:2023-10-10 21:10

最满意答案

我只能猜测,因为我没有装配给我。

我猜测你得到一个段错误的行被编译成如下形式:

mov ds:[offset mx], 0x407cafe

其中offset mx是程序数据段(如果是静态变量)或堆栈中(如果它是自动变量)的mx偏移量。 无论哪种方式,这个偏移量都是在编译时计算的,无论DS指向什么,都会使用这个偏移量。

现在你在这里做的是创建一个新的段,其基地址为mx ,其限制为0x40x4fff (取决于你未指定的G-bit )。

如果G-bit为0,则限制为0x4 ,并且由于mx位于原始DS地址0x00x4之间的可能性0x4 ,因此当您访问新段中的mx偏移量时, 。

如果G-bit是1,那么限制是0x4fff 。 现在只有当原始mx位于0x4fff之上时0x4fff0x4fff

考虑到新的细分市场的基础是mx ,你可以通过以下方式访问mx

mov ds:[0], 0x407cafe

不过,我不知道如何用C编写它。


I can only guess, since I don't have the assembly available to me.

I'm guessing that the line at which you get a segfault is compiled to something like:

mov ds:[offset mx], 0x407cafe

Where offset mx is the offset to mx in the program's data segment (if it's a static variable) or in the stack (if it's an automatic variable). Either way, this offset is calculated at compile time, and that's what will be used regardless of what DS points to.

Now what you've done here is create a new segment whose base is at the address of mx and whose limit is either 0x4 or 0x4fff (depending on the G-bit which you didn't specify).

If the G-bit is 0, then the limit is 0x4, and since it's highly unlikely that mx is located between addresses 0x0 and 0x4 of the original DS, when you access the offset to mx inside the new segment you're crossing the limit.

If the G-bit is 1, then the limit is 0x4fff. Now you'll get a segfault only if the original mx was located above 0x4fff.

Considering that the new segment's base is at mx, you can access mx by doing:

mov ds:[0], 0x407cafe

I don't know how I'd go about writing that in C, though.

相关问答

更多
  • GDT基本上是包含各种GDT条目的结构。 lgdtl是将全局描述符表加载到gdt寄存器的指令。 那么,回答你的问题:0x10f018是GDT基地址。 如果查看代码,您会发现GDT定义为结构,0x10f018是该结构的地址(根据您的反汇编),在GDT结构中最多可以有8192个条目。 所以,是的GDT寄存器保存GDT结构的基址。 lgdt用于设置gdt,它的格式如下: lgdt maddr 。 并且,在设置GDT之前,打印寄存器内容的计划将无效,因为设置GDT的唯一方法是使用lgdt 。 希望这会有所帮助! 另 ...
  • 我只能猜测,因为我没有装配给我。 我猜测你得到一个段错误的行被编译成如下形式: mov ds:[offset mx], 0x407cafe 其中offset mx是程序数据段(如果是静态变量)或堆栈中(如果它是自动变量)的mx偏移量。 无论哪种方式,这个偏移量都是在编译时计算的,无论DS指向什么,都会使用这个偏移量。 现在你在这里做的是创建一个新的段,其基地址为mx ,其限制为0x4或0x4fff (取决于你未指定的G-bit )。 如果G-bit为0,则限制为0x4 ,并且由于mx位于原始DS地址0x0 ...
  • 您可以通过unix域套接字将文件描述符传递给另一个进程。 以下是传递这样一个文件描述符的代码,取自Unix网络编程 ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd) { struct msghdr msg; struct iovec iov[1]; #ifdef HAVE_MSGHDR_MSG_CONTROL union { struct cmsghdr cm; c ...
  • 我从使用术语GDT的角度来假设您正在询问x86和/或x86-64处理器。 每个x86处理器(准确地说,硬件线程)都有自己独立的IDTR和GDTR寄存器。 这允许,但不要求操作系统在每个处理器上使用不同的IDT和GDT。 x86中的中断向量空间为8位,其中32位保留,留下224个中断。 在许多平台中,这不是足够明显的中断向量。 通过在每个处理器上使用不同的IDT,操作系统可以为每个处理器分配最多224个不同的中断向量。 (但是,你不应该假设所有的操作系统都这么做。) 相比之下,GDT最多可以容纳8191个描述 ...
  • 当它表示don't use those [interrupts 0-31] for APIs or IRQs ,这意味着你不应该将它们用于除保留的异常之外的功能。 您确实需要为这些中断定义处理程序,以便在发生异常时对其进行处理。 有关其中断编号和描述的异常列表,请参见OSDev的异常页面 。 当处理器启动时,它处于实模式。 在此模式下,异常较少,因此保留较少的中断来处理它们。 只要处理器处于实模式,就可以安全地使用中断8-15进行IRQ。 在保护模式下启用中断之前,需要将IRQ重新映射到不同的中断。 有关如 ...
  • http://www.internals.com/articles/protmode/protmode.htm Hans-Peter Messmer有一本名为“The Indespensible PC Hardware Book”的书,详细介绍了这本书。 http://www.internals.com/articles/protmode/protmode.htm There is a book called 'The Indespensible PC Hardware Book' by Hans-Pete ...
  • 这是一个简化的例子: $ fd_leaker() { while :; do read a < <(pwd); c=(/proc/$$/fd/*); c=${#c[@]}; echo $c; done; } $ fd_leaker 这个不是通过使用/bin/true修复的,但它主要通过使用(exit 0)来修复但是我得到“bash:echo:写错误:系统调用中断”错误使用“修复”或者如果我使用/bin/pwd而不是内置的pwd 。 它似乎也是特定的read 。 我试过grep . < <(pwd) > ...
  • 通过逐个插入大列表中的值而不是值列表来解决问题。 for(Object listItem: java.util.list){ llist.update(Value.get(listItem)) } Solved the issue by upserting the value in the large list one by one instead of a value list. for(Object listItem: java.util.list){ llist.update(Value.get(l ...
  • 可以使用未记录的NT API,特别是NtSetLdtEntries。 请注意,Windows x86-64不会设置LDT,因此这仅适用于x86。 这是一些代码。 It's possible using undocumented NT API, specifically NtSetLdtEntries. Note that Windows x86-64 does not set up an LDT so this only works on x86. Here's some code.
  • Linux / x86-64并没有真正使用段寄存器,期望线程本地存储(它们可能由内核管理,而不仅仅是libc)。 它主要是设置它们的内核。 请阅读Linux x86-64 ABI以获取详细信息(或Linux ia32 ABI for 32位x86); 在这里看到32位的其他参考, 这里是64位)。 阅读更多关于系统调用(2) & execve(2) & set_thread_area(2) & modify_ldt(2)的信息 我想线程创建可能会设置一些段寄存器(请参阅clone(2) ...)。 研究C标 ...

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)