如何同步线程?

时间:2011-05-08 09:04:25

标签: c unix synchronization pthreads

我在这段代码中使用了线程。但是当我在shell中执行这段代码时,有些线程没有打印这一行。

printf("\ti'm %dth thread:)", j);  
printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);

此外,甚至一些线程也会打印此行两次。这个过程发生了什么?以及如何重新组织此代码以便线程只打印一次线?

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

typedef struct {char op; int byte; int seq; int no_file; } ARRAY; 

ARRAY *arr;

void *thread_operation(void *arg){
    int j =*((int*)arg);
    seq = arr[j].seq;
    int no_file = arr[j].no_file;
    printf("\ti'm %dth thread:)", j);
    printf("\t%c  %d  %d  %d \n", arr[j].op, arr[j].byte, seq, no_file);
}

int main()
{
    int err, j, i = 10;
    long int tid;
    arr = (ARRAY*)malloc(sizeof(ARRAY) * i);
    srand(time(NULL));
    for (i = 0; i <= 10; i++){
        arr[i].op = 'r';
        arr[i].byte = (rand() % 10);
        arr[i].seq = i;
        arr[i].no_file = i + 10;
}

    for(j = 0; j < 10; j++){
        printf("creating %dth thread.....", j);
        err = pthread_create(&tid, NULL, thread_operation, &j);
        if(err != 0)
        printf("%s\n", strerror(err));
        printf("%dth done\n", j);
    }

    return 0;
}

这是我的电脑的结果

creating 0th thread.....0th done
creating 1th thread.....    i'm 0th thread:)    r  9  0  10
1th done
creating 2th thread.....    i'm 2th thread:)    r  3  2  12
    i'm 2th thread:)    r  3  2  12
2th done
creating 3th thread.....    i'm 3th thread:)    r  6  3  13
3th done
creating 4th thread.....    i'm 4th thread:)    r  9  4  14
4th done
creating 5th thread.....    i'm 5th thread:)    r  3  5  15
5th done
creating 6th thread.....    i'm 6th thread:)    r  2  6  16
6th done
creating 7th thread.....    i'm 7th thread:)    r  2  7  17
7th done
creating 8th thread.....8th done
creating 9th thread.....    i'm 8th thread:)    r  6  8  18
9th done
    i'm 9th thread:)    r  8  9  19  
    i'm 9th thread:)    r  8  9  19

3 个答案:

答案 0 :(得分:6)

你需要使用互斥量来避免竞争条件,并且还需要使用pthread_join在进程终止之前同步所有线程。

Mutexes允许您在其中一个线程使用共享资源执行操作时停止某些线程(请参阅man pthread_mutex_lock,pthread_mutex_init)

pthread_join在您的代码中是必不可少的,因为它强制您的主线程等待您创建的其他线程,如果您不使用它,您不确定当主线程从主线程返回时所有线程都将完成主

答案 1 :(得分:2)

有些人打印两次的原因(例如第9号线程)是因为你传递一个指向你的循环变量的指针作为thread_operation的输入。

for(j = 0; j < 10; j++){
    err = pthread_create(&tid, NULL, thread_operation, &j);<---here

&amp; j最终被thread_operation取消引用:

void *thread_operation(void *arg){
    int j =*((int*)arg);<---here

但是此时循环可能已经提前,j的值(在线程操作中)将是现在循环中出现的j。解决这个问题的方法是不将指针,而是j的值传递给线程构造函数。更改pthread_create以传递值:

pthread_create(&tid, NULL, thread_operation, (void*) j);

并在你的线程中将值转换为线程参数:

int j =(int)arg;

现在从技术上讲,这依赖于intvoid*大小相同的事实,而一般情况下它们不是。但只要你没有使用巨大的int值,这就行了。

对于所有其他问题,@ Intrepidd正确使用pthread_join确保在所有线程完成之前进程不会退出。

答案 2 :(得分:1)

在线程之间使用printf不完整的行通常不起作用。您可能会完全损坏输出。此外,行显示在屏幕上的顺序通常不是执行顺序,而是线程访问共享资源stdout的顺序。