線程2-線程同步

概念

線程是可以共享資源變量的,當多個線程同時寫一個資源變量時就會出現線程同步問題造成讀寫不一致。通常採用鎖機制來實現線程同步。

1 互斥量:鎖機制,確保同一時刻只有一個線程訪問共享資源。

常用API包括:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);

不採用互斥量的多線程問題:

void *func2(void *p)
{
    char *file_name = "/tmp/out";
    FILE *fp;
    char linebuf[1024];
    fp = fopen(file_name, "r+");
    if(fp == NULL)
    {
        perror("fopen()");
        exit(-1);
    }
    fgets(linebuf, 1024, fp);
    fseek(fp, 0, SEEK_SET);
    fprintf(fp, "%d\n", atoi(linebuf)+1);
    fclose(fp);
    pthread_exit(NULL);
}

void test2()
{
    int err, num = 20;
    pthread_t tid[num];
    for(int i=0; i<num; i++)
    {
        err = pthread_create(tid+i, NULL, func2, NULL);
        if(err)
        {
            fprintf(stdout,"pthread_create %s\n", strerror(err));
            exit(1);
        }
    }
}

採用互斥量的多線程:

void *func3(void *p)
{
    char *file_name = "/tmp/out";
    FILE *fp;
    char linebuf[1024];
    fp = fopen(file_name, "r+");
    if(fp == NULL)
    {
        perror("fopen()");
        exit(-1);
    }
    pthread_mutex_lock(&mut);
    fgets(linebuf, 1024, fp);
    fseek(fp, 0, SEEK_SET);
    fprintf(fp, "%d\n", atoi(linebuf)+1);
    fclose(fp);
    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}

void test3()
{
    int err, num = 20;

    pthread_t tid[num];
    for(int i=0; i<num; i++)
    {
        err = pthread_create(tid+i, NULL, func3, NULL);
        if(err)
        {
            fprintf(stdout,"pthread_create %s\n", strerror(err));
            exit(1);
        }
    }
    for(int i=0; i<num; i++)
        pthread_join(tid[i], NULL);
    pthread_mutex_destroy(&mut);
    exit(0);
}

4個線程依次輸出abcd,如何實現?

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include  <string.h>

static pthread_mutex_t mut[4];

int next(int n)
{
    if(n+1 == 4)
        return 0;
    return n+1;
}

void *func(void *p)
{
    int i = (int) p;
    while(1){
        pthread_mutex_lock(mut+i);  //鎖自己接下一個人的鎖
        switch (i)
            {
                case 0:
                    putchar('a');
                    break;
                case 1:
                    putchar('b');
                    break;
                case 2:
                    putchar('c');
                    break;
                case 3:
                    putchar('d');
                    break;
                default:
                    break;
            }
        pthread_mutex_unlock(mut+next(i));
    }
    putchar('\n');

    pthread_exit(NULL);
}
int main(int argc, char **argv)
{

    int i,err;

    int num = 4;
    pthread_t tid[num];

    for(i=0;i<num;i++)
    {
        pthread_mutex_init(mut+i, NULL);
        pthread_mutex_lock(mut+i);
        err = pthread_create(tid+i, NULL, func, (void *)i); //i一個地址被201個指針指向
        if(err)
        {
            fprintf(stdout,"pthread_create %s\n", strerror(err));
            exit(1);
        }
    }
    alarm(2);   //定時殺死進程
    pthread_mutex_unlock(mut);
    for(i=0;i<num;i++)
    {
        pthread_join(tid[i], NULL);
    }
    pthread_mutex_destroy(&mut);

    exit(0);
}

2 條件變量:是一種通知法機制,避免資源不夠時的忙等。

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include  <string.h>

#define LEFT  30000000
#define RIGHT 30011911
#define THRUNM 3
//全局變量負責記錄資源
static int num=0;
//互斥量
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t condt = PTHREAD_COND_INITIALIZER;

void *func(void *p)
{
    int i,mark,j;
    int number = (int) p;
    while(1)
    {
        pthread_mutex_lock(&mut);
        while(num == 0)
        {
            pthread_cond_wait(&condt, &mut);
        }
        if(num == -1)
        {
            pthread_mutex_unlock(&mut);
            break;
        }
        i = num;
        num = 0;
        pthread_cond_broadcast(&condt);
        pthread_mutex_unlock(&mut);
        mark =1;
        for(j=2; j<i/2;j++)
        {
            if(i%j == 0)
            {
                mark =0;
                break;
            }
        }
        if(mark) {
            printf("%d號線程計算出來:%d is primer\n", number,i);
        }
    }

    pthread_exit(NULL);
}
int main(int argc, char **argv)
{
    int i,err;
    pthread_t tid[THRUNM];
    for(i=0;i<THRUNM;i++)
    {
        err = pthread_create(tid+i, NULL, func, (void *)i); //i一個地址被THRUNM個指針指向
        if(err)
        {
            fprintf(stdout,"pthread_create %s\n", strerror(err));
            exit(1);
        }
    }
    //main線程負責下發任務
    for(i=LEFT;i<=RIGHT;i++)
    {
        pthread_mutex_lock(&mut);
        //任務還在未被搶走
        while(num != 0)
        {
            pthread_cond_wait(&condt, &mut);
        }
        num = i;
        pthread_cond_signal(&condt);
        pthread_mutex_unlock(&mut);
    }
    pthread_mutex_lock(&mut);
    while(num != 0) {
        pthread_mutex_unlock(&mut);
        sched_yield();
        pthread_mutex_lock(&mut);
    }
    //退出線程
    num = -1;
    pthread_cond_broadcast(&condt);
    pthread_mutex_unlock(&mut);
    for(i=0;i<THRUNM;i++)
    {
        pthread_join(tid[i], NULL);
    }
    pthread_mutex_destroy(&mut);
    pthread_cond_destroy(&condt);
    exit(0);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章