请教下 mac 环境下,我这几行代码的问题在哪里

2023-09-11 15:59:34 +08:00
 awanganddong
    
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>


sem_t mutex;

void *my_thread() {
    while (1) {
        //判断信号量是否大于 0 ,如果大于 0 ,执行减一操作,并继续 sem_wait 之后的代码;如果当前 sem 等于 0 ,阻塞等待直至大于零
        // (大于零之后执行减一操作,继续 sem_wait 之后的代码)
        printf("测试数据 1");
        sem_wait(&mutex);
        //信号量值加一,直接返回;
        printf("测试数据 2");
        sem_post(&mutex);
        printf("测试数据 3");
        break;
    }
    return 0;
}

int main() {
    pthread_t thread_1, thread_2; //声明线程 ID
//    sem_open()创建一个新的 POSIX 信号量或打开一个现有的信号量。信号灯由名称标识。有关名称构造的详细信息,请参见 sem_overview(7)。
//    oflag 参数指定用于控制调用操作的标志。 (可以通过包含来获得标志值的定义。)如果在 oflag 中指定 O_CREAT ,则如果信号灯尚不存在,则会创建该信号灯。
//    信号量的所有者(用户 ID)设置为调用过程的有效用户 ID 。组所有权(组 ID)设置为调用过程的有效组 ID 。如果在 oflag 中同时指定了 O_CREAT 和 O_EXCL ,
//    则如果已经存在具有给定名称的信号灯,则将返回错误。
//    如果在 oflag 中指定 O_CREAT ,则必须提供两个附加参数。mode 参数指定要放置在新信号量上的权限,就像 open(2)一样。
//    (可以通过包含。获得权限位的符号定义。)权限设置针对进程 umask 进行掩码。应该向将访问信号量的每个用户类别都授予读取和写入权限。
//    value 参数指定新信号量的初始值。如果指定了 O_CREAT ,并且已经存在具有给定名称的信号灯,则将忽略 mode 和 value
    mutex = *sem_open("mutex", O_CREAT, S_IRWXU, 1);
//    Name 用于标识信号量的名字
//    Oflag 被设置为 O_CREAT 用来创建一个信号量(如果和 0_EXCL 一起,当这个信号量已经存在时候这个调用将会失败)
//    mode_t 控制新的信号量的访问权限
//    Value 指定信号量的初始化值
//    ( 1 ) tidp:事先创建好的 pthread_t 类型的参数。成功时 tidp 指向的内存单元被设置为新创建线程的线程 ID 。
//    ( 2 ) attr:用于定制各种不同的线程属性。APUE 的 12.3 节讨论了线程属性。通常直接设为 NULL 。
//    ( 3 ) start_rtn:新创建线程从此函数开始运行。无参数是 arg 设为 NULL 即可。
//    ( 4 ) arg:start_rtn 函数的参数。无参数时设为 NULL 即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入。(以下举例)
    //向线程函数传递参数
    pthread_create(&thread_1, NULL, &my_thread, NULL);
    pthread_create(&thread_2, NULL, &my_thread, NULL);
    //以阻塞的方式等待 thread 指定的线程结束。当函数返回时,被等待线程的资源被收回。
    // 如果线程已经结束,那么该函数会立即返回。并且 thread 指定的线程必须是 joinable 的
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);
    sem_unlink("mutex");
    return 0;
}

    ```
    报错是这个
    zsh: segmentation fault  ./a.out
1407 次点击
所在节点    C
4 条回复
ysc3839
2023-09-11 16:36:38 +08:00
调试看看吧,一般能直接定位到出问题的点。

另外如果没什么特殊需求的话(比如限制只能用 C),个人建议用 C++标准库里面的 thread mutex 等,比 POSIX API 好用。
cosiner
2023-09-11 16:48:26 +08:00
`mutex = *sem_open`, 为什么要用 * 解引用?, 那块内存你不一定有访问权限的, 还可能有其他原因, 具体我也不太懂
q8515620
2023-09-11 17:17:42 +08:00
segmentfalt 是访问了没有权限的内存地址,发生在 sem_wait(&mutex)这里。
mutex 是个全局变量,&mutex 是这个变量所在的内存地址,而不是你以为的信号量的地址。
你将 sem_open()返回的信号量的地址直接解引用为该地址所指向的“值”并赋值(这里应该是拷贝了一份)给了 mutex ,这样的话,你直接把信号量的地址丢弃了。

正确使用方法:
sem_t *mutex; // 将 mutex 声明为指向 sem_t 的指针
mutex = sem_open("mutex", O_CREAT, S_IRWXU, 1);
sem_wait(mutex);
awanganddong
2023-09-12 22:49:02 +08:00
谢谢大家的解答了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/972763

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX