POSIX多线程程序设计(第3章:同步)

    当多个线程对共享数据同时操作时,为了保证共享数据的一致性,需要同步线程的读写操作。

1互斥量

1.1函数

1创建和销毁互斥量

#include <pthread.h>

/*动态创建和销毁*/

int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

返回值:若成功返回0,否则返回错误编号

 

/*静态初始化,不需要销毁*/

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2加锁和解锁互斥量

#include <pthread.h>

/*加锁,如果互斥量已上锁,调用线程将阻塞直到互斥量被解锁。*/

int pthread_mutex_lock(pthread_mutex_t *mutex);

/*解锁,不能解锁由其他线程锁住的互斥量*/

int pthread_mutex_unlock(pthread_mutex_t *mutex);

/*尝试加锁,如果互斥量已上锁,调用线程返回失败返回EBUSY而不会阻塞*/

int pthread_mutex_trylock(pthread_mutex_t *mutex);

返回值:若成功返回0,否则返回错误编号

1.2应用

/* errors.h*/
#ifndef __errors_h
#define __errors_h

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

#ifdef DEBUG
#define DPRINTF(arg) printf arg
#else
#define DPRINTF(arg)
#endif


#define err_abort(code,text) do{\
fprintf(stderr, "%s at \"%s\":%d: %s\n",\
text, __FILE__, __LINE__, strerror(code));\
abort();\
}while(0)

#define errno_abort(text) do {\
fprintf(stderr, "%s at \"%s\":%d: %s\n", \
text, __FILE__, __LINE__, strerror (errno)); \
abort();\
}while(0)

#endif
#include "errors.h"
#include <time.h>
#include <pthread.h>

typedef struct alarm_tag
{
    struct alarm_tag *link;
    time_t time;
    int    seconds;
    char message[64];
}alarm_t;

pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;/*互斥量*/
alarm_t *alarm_list = NULL;  /*全局变量,此处为需要同步的共享资源*/

void *alarm_thread(void *arg)
{
    alarm_t *alarm;
    int sleep_time;
    time_t now;
    int status;

    while (1)
    {
        /*加锁*/
        pthread_mutex_lock(&alarm_mutex);
   
        alarm = alarm_list;
        if (alarm == NULL)
        {
            /*闹钟链表为空,则休眠1s*/
            sleep_time = 1;
        }
        else
        {
            alarm_list = alarm->link;
            now = time(NULL);
            if (alarm->time <= now)
            {
                sleep_time = 0;
            }
            else
            {
                sleep_time = alarm->time - now;
            }
#ifdef DEBUG
            printf("[waiting: %d(%d)\"%s\"]\n", alarm->time, sleep_time, alarm->message);
#endif
        }

        /*解锁*/
        pthread_mutex_unlock(&alarm_mutex);
        
        if (sleep_time > 0)
        {
            /*开始休眠*/
            sleep(sleep_time);
        }
        else
        {
            /*将处理器交给另一个等待运行的线程,如果没有就绪的线程则立即返回*/
            sched_yield();
        }

        if (alarm != NULL)
        {
            printf("(%d) %s\n", alarm->seconds, alarm->message);
            free(alarm);
        }
    }
}


int main(int argc, char *argv[])
{
    int status;
    char line[128];
    alarm_t *alarm, **last, *next;
    pthread_t thread;

    status = pthread_create(&thread, NULL, alarm_thread, NULL);
    if (status != 0)
    {
        err_abort(status, "Create alarm thread");
    }

    while (1)
    {
        printf("Alarm> ");
        if (fgets(line, sizeof(line), stdin) == NULL)
            exit(0);

        if (strlen(line) <= 1)
            continue;

        alarm = (alarm_t *)malloc(sizeof(alarm_t));
        if (alarm == NULL)
        {
            errno_abort("allocate alarm");
        }
        
        if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2)
        {
            fprintf(stderr, "Bad command\n");
            free(alarm);
        }
        else
        {
            /*加锁*/
            pthread_mutex_lock(&alarm_mutex);

            alarm->time = time(NULL) + alarm->seconds;
            last = &alarm_list;
            next = *last;
            while (next != NULL)
            {
                if (next->time >= alarm->time)
                {
                    alarm->link = next;
                    *last = alarm;
                    break;
                }
                last = &next->link;
                next = next->link;
            }

            if (next == NULL)
            {
                *last = alarm;
                alarm->link = NULL;
            }
#if DEBUG
            printf("[list: ");
            for (next = alarm_list; next != NULL; next = next->link)
                printf("%d(%d)[\"%s\"]", next->time, next->time - time(NULL), next->message);
            printf("]\n");

#endif
            /*解锁*/
            pthread_mutex_unlock(&alarm_mutex);
        }
    }
}

2条件变量

2.1函数

1条件变量初始化

#include <pthread.h>

int pthread_cond_init(pthread_cond_t * cond, pthread_condattr_t * attr);

int pthread_cond_destroy(pthread_cond_t *cond);

返回值:成功返回0,失败返回错误码

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*静态初始化*/

2等待条件变量

头文件

#include <pthread.h>

函数

int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);

参数

cond: 条件变量

mutex:互斥量,用来同步共享数据。

返回值

成功返回0,失败返回错误码。等待条件变量总是返回锁住的互斥量。

说明

在一个条件变量上等待会导致一下原子操作:

      释放相关互斥量,等待其他线程发给该条件变量信号或广播该条件变量。当等待条件变量时,互斥量必须始终为释放的,这样其他线程才有机会锁住互斥量,修改条件变量;当线程从条件变量等待中醒来时,它重新继续锁住互斥量。


头文件

#include <pthread.h>

函数

int pthread_cond_timedwait(pthread_cond_t *cond,

                                                  pthread_mutex_t *mutex,

                       struct timespec *timeout);

参数

cond:条件变量

mutex:互斥量

timeout:等待的时间值,用秒数tv_sec或分秒数tv_nsec来表示。

         struct timespec{

             time_t tv_sec;/**/

            long tv_nsec;/*纳秒*/

         }; 

    timeout这个时间值是绝对数而不是相对数,例如等待3分钟,则需要把当前时间再加上3分钟再转换到timespec结构。

返回值

成功返回0,失败返回错误码

3唤醒等待条件变量的线程

#include <pthread.h>

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

返回值:成功返回0,失败返回错误码

2.2应用

#include "errors.h"
#include <time.h>
#include <pthread.h>

typedef struct alarm_tag
{
    struct alarm_tag *link;
    time_t time;
    int    seconds;
    char message[64];
}alarm_t;

pthread_mutex_t alarm_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t   alarm_cond = PTHREAD_COND_INITIALIZER;
alarm_t *alarm_list = NULL;
time_t current_alarm = 0;

void alarm_insert(alarm_t *alarm)
{
    int status;
    alarm_t **last, *next;

    last = &alarm_list;
    next = *last;
    while (next != NULL)
    {
        if (next->time >= alarm->time)
        {
            alarm->link = next;
            *last = alarm;
            break;
        }
        last = &next->link;
        next = next->link;
    }

    if (next == NULL)
    {
        *last = alarm;
        alarm->link = NULL;
    }

#if DEBUG
    printf("[list: ");
    for (next = alarm_list; next != NULL; next = next->link)
        printf("%d(%d)[\"%s\"]", next->time, next->time - time(NULL), next->message);
    printf("]\n");
#endif

    if (current_alarm ==0 || alarm->time < current_alarm)
    {
        current_alarm = alarm->time;
        status = pthread_cond_signal(&alarm_cond);
        if (status != 0)
        {
            err_abort(status, "signal cond");
        }
    }
}



void *alarm_thread(void *arg)
{
    alarm_t *alarm;
    struct timespec cond_time;
    time_t now;
    int status;
    int expired;

    /*加锁*/
    pthread_mutex_lock(&alarm_mutex);
    while (1)
    {
        current_alarm = 0;
        while (alarm_list == NULL)
        {
            /*链表为空,则等待*/
            pthread_cond_wait(&alarm_cond, &alarm_mutex);
        }

        /*摘取alarm链表的第一个元素*/
        alarm = alarm_list;
        alarm_list = alarm->link;
           
        now = time(NULL);
        expired = 0;
        if (alarm->time > now)
        {
#ifdef DEBUG
            printf("[waiting: %d (%d)\"%s\"]\n]", alarm->time, alarm->time - time(NULL), alarm->message);
#endif
            cond_time.tv_sec = alarm->time;
            cond_time.tv_nsec = 0;
            current_alarm = alarm->time;
            while (current_alarm == alarm->time)
            {
                status = pthread_cond_timedwait(&alarm_cond, &alarm_mutex, &cond_time);
                if (status == ETIMEDOUT)
                {
                    expired = 1;
                    break;
                }
                if (status != 0)
                {
                    err_abort(status, "cond timewait");
                }
            }

            if (!expired)
            {
                alarm_insert(alarm);
            }
        }
        else
        {
            expired = 1;
        }

        if (expired)
        {
            printf("(%d) %s\n", alarm->seconds, alarm->message);
            free(alarm);
        }
    }
}


int main(int argc, char *argv[])
{
    int status;
    char line[128];
    alarm_t *alarm;
    pthread_t thread;

    status = pthread_create(&thread, NULL, alarm_thread, NULL);
    if (status != 0)
    {
        err_abort(status, "Create alarm thread");
    }

    while (1)
    {
        printf("Alarm> ");
        if (fgets(line, sizeof(line), stdin) == NULL)
            exit(0);

        if (strlen(line) <= 1)
            continue;

        alarm = (alarm_t *)malloc(sizeof(alarm_t));
        if (alarm == NULL)
        {
            errno_abort("allocate alarm");
        }
        
        if (sscanf(line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2)
        {
            fprintf(stderr, "Bad command\n");
            free(alarm);
        }
        else
        {
            pthread_mutex_lock(&alarm_mutex);

            alarm->time = time(NULL) + alarm->seconds;
            alarm_insert(alarm);
           
            pthread_mutex_unlock(&alarm_mutex);
        }
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值