如何在C中使用互斥锁

时间:2011-09-05 02:22:35

标签: c multithreading pthreads mutex

我对在C中使用多个互斥锁感到困惑。

int main() {

        pthread_t thread1;
        char *message1 = "Thread 1";
        int  r;
        pthread_mutex_init(&mutex1, NULL);
        pthread_mutex_init(&mutex2, NULL);

        pthread_mutex_lock(&mutex1);

        r = pthread_create( &thread1, NULL, print_message_function, (void*) message1);

        printf("Parent 1\n");


        pthread_mutex_lock(&mutex2);
        printf("Parent 2\n");
        pthread_mutex_unlock(&mutex2);


        pthread_mutex_unlock(&mutex1);


        pthread_join( thread1, NULL);

        printf("Thread 1 returns: %d\n",r);
        return 0;
}

void *print_message_function( void *str ) {

        pthread_mutex_lock(&mutex1);
        char *message;
        message = (char *) str;
        printf("Child 1 received message: %s \n", message);


        pthread_mutex_lock(&mutex2);
        printf("child 2\n");
        pthread_mutex_unlock(&mutex2);




        pthread_mutex_unlock(&mutex1);

        return NULL;
}

输出

Parent 1
Parent 2
Child 1 received message: Thread 1 
child 2
Thread 1 returns: 0

我想要的是

Parent 1
Child 1 received message: Thread 1 
Parent 2
child 2
Thread 1 returns: 0

3 个答案:

答案 0 :(得分:5)

当您致电pthread_create时,您已锁定mutex1。这意味着调用pthread_mutex_lock(&mutex1);的每个其他线程都将等待互斥锁被解锁。这就是当您创建第二个线程时发生的情况:mutex1已被锁定,因此第二个线程无法进入临界区但需要等待互斥锁解锁。这发生在main函数的末尾。

您需要重新组织代码才能获得所需的输出。

但是,要获得此类结果,您应该检查同步系统,例如semaphorescondition variables;它们将提供更清晰,更简单的线程同步方式 您还可以查看本教程:POSIX Threads Programming


使用信号量的简单解决方案(未经测试,但它应该有效):

#include <stdio.h>
#include <semaphore.h>

sem_t sem1, sem2;

void* f(void* str) {

    sem_wait(&sem1);
    printf("Child 1 received message: %s \n",(char*)str);

    sem_post(&sem2);
    sem_wait(&sem1);

    printf("Child 2\n");

    return NULL;
}



int main (int argc, const char * argv[]) {

    pthread_t thread;
    char* message = "Thread 1";

    int r;

    sem_init(&sem1,0,0);
    sem_init(&sem2,0,0);

    r = pthread_create(&thread, NULL, f, (void*)message);
    sem_post(&sem1);
    sem_wait(&sem2);

    printf("Parent 2\n");

    sem_post(&sem1); 

    pthread_join(thread1, NULL);
    printf("Thread 1 returns: %d\n",r);

    return 0;
}

答案 1 :(得分:3)

单独的互斥锁不适合执行您想要的那种紧密互锁执行 - 它们的正常用途是保护对共享数据结构的访问。这是因为他们的目的是说“Thing A不应该与Thing B同时发生”,但是他们没有说出Thing A或Thing B是第一次还是第二次发生

您可以使用互斥锁和条件变量,但在这种情况下,您的问题最匹配的是pthreads Barrier对象:

#include <stdio.h>
#include <pthread.h>

pthread_barrier_t barrier;

void *print_message_function( void *str )
{
        char *message;
        message = (char *) str;

        pthread_barrier_wait(&barrier); /* Barrier point 1 */
        /* (wait until parent prints first message) */

        printf("Child 1 received message: %s \n", message);

        pthread_barrier_wait(&barrier); /* Barrier point 2 */
        /* (allow parent to proceed and print second message) */

        pthread_barrier_wait(&barrier); /* Barrier point 3 */
        /* (wait for parent to print second message) */

        printf("child 2\n");

        return NULL;
}

int main()
{

        pthread_t thread1;
        char *message1 = "Thread 1";
        int  r;

        pthread_barrier_init(&barrier, NULL, 2);

        r = pthread_create( &thread1, NULL, print_message_function, (void*) message1);

        printf("Parent 1\n");

        pthread_barrier_wait(&barrier); /* Barrier point 1 */
        /* (allow child to proceed and print first message) */

        pthread_barrier_wait(&barrier); /* Barrier point 2 */
        /* (wait for child to print first message) */

        printf("Parent 2\n");

        pthread_barrier_wait(&barrier); /* Barrier point 3 */
        /* (allow child to proceed and print second message) */

        pthread_join( thread1, NULL);
        /* (wait for child to exit) */

        printf("Thread 1 returns: %d\n",r);
        return 0;
}

请注意,尝试以这种方式紧密地锁定线程的执行是通常不是 - 实际上,您已经非常努力地确保线程不会并行执行所有,这首先是线程的全部要点。如果你发现自己在一个真实的项目中这样做,那就表明你应该仔细重新思考你的设计。

答案 2 :(得分:2)

我认为您需要尽快解锁mutex1。您在printf("Parent 2\n");之后将其解锁,因此thread1仍然处于锁定状态,等待pthread_mutex_lock(&mutex1);

当thread1启动时,它的第一步是在等待互斥(名称中的线索)锁定mutex1时锁定。所以它被暂停了。

然后你:

    printf("Parent 1\n");

    pthread_mutex_lock(&mutex2); <-- lock 2 is unleased but thread one is waiting on mutex1
    printf("Parent 2\n");