day_17_可重入函数、线程同步

一、可重入函数的使用

  线程函数尽量保持可重入性,不可重入函数会造成的临界资源访问的问题;
如:

/* 不可重入函数造成的临界资源访问问题 */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int count = 0;
// 声明一个mutex锁类型
pthread_mutex_t mutex;

void* doit(void* arg)
{
    int val, i;
    for(i = 0;i < 5000;i++)
    {   
        // 加锁
        pthread_mutex_lock(&mutex);
        val = count;
        val++;
        printf("val = %d\n", val);
        count = val;
        // 解锁
        pthread_mutex_unlock(&mutex);
    }   
    return NULL;
}                                                                                              

int main(void)
{
    int res;
    pthread_t tid, cid;
    // 初始化mutex锁类型
    pthread_mutex_init(&mutex, NULL);
    // 创建两个新的线程
    pthread_create(&tid, NULL, doit, NULL);
    pthread_create(&cid, NULL, doit, NULL);
    // 等待线程的汇合
    pthread_join(tid, NULL);
    pthread_join(cid, NULL);
    // 销毁mutex锁类型
    pthread_mutex_destroy(&mutex);
    return 0;
}

二、线程的同步

2.1 mutex锁

  当一个线程需要使用临界资源时,线程会对该资源加锁,待使用完毕后,才解锁该资源。

mutex锁的类型是:pthread_mutex_t

typedef union                                                                                  
{
    struct __pthread_mutex_s
    {
        int __lock;
        unsigned int __count;
        int __owner;
        unsigned int __nusers;
        int __kind;
        short __spins;
        short __elision;
        __pthread_list_t __list;
    } __data;
    char __size[40];
    long int __align;
} pthread_mutex_t;

mutex锁的静态初始化

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
(1)pthread_mutex_init(3)
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t, *mutexattr);

功能:
  主要用于初始化一个mutex锁;

参数:
  第一个参数:指定要初始化的mutex锁;
  第二个参数:指定初始化mutex锁的属性,给NULL表示缺省属性;

返回值:
  总是返回0;

(2)pthread_mutex_lock(3)
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);

功能:
  主要用于将指定的mutex设置为lock状态,实现加锁效果。如果mutex之前处于unlocked状态,立即加锁,并返回;如果mutex之前处于locked状态,则挂起等待mutex变为unlocked状态后再加锁。

参数:
  第一个参数:指定要设置为locked状态的mutex锁;

返回值:
  success —- 0,error —- 非0;

(3)pthread_mutex_trylock(3)
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);

功能:
  主要用于将指定的mutex设置为lock状态,实现加锁效果。如果mutex之前处于unlocked状态,立即加锁,并返回;如果mutex之前处于locked状态,立即返回错误,并设置errno为EBUSY。

参数:
  mutex:指定要设置为locked状态的mutex锁;

返回值:
  success —- 0,error —- 非0;

(4)pthread_mutex_unlock(3)
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);

功能:
  主要用于将指定的mutex锁设置为unlocked状态,实现解锁效果。

参数:
  第一个参数:指定要解开的mutex锁;

返回值:
  success —- 0,error —- 非0;

(5)pthread_mutex_destroy(3)
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);

功能:
  主要用于销毁指定的mutex锁;

参数:
  第一个参数:指定要销毁的mutex锁;

返回值:
  success —- 0,error —- 非0;

注意:
  以上这些函数都是对pthread_mutex_t类型变量的操作。使用时一定要注意锁的范围,即使用到临界资源的时候,加锁;不使用临界资源的时候解锁。


2.2 条件变量

  线程间同步的一种情况,有两个线程A和B。线程A需要等某个条件成立的时候,才能继续往下执行,这时候,条件不成立,线程A阻塞等待。线程B的执行使这个条件变为成立。线程A得知条件成立了,线程A继续往下执行。这样的清况称为条件变量。

条件变量的类型是:pthread_cond_t

typedef union
{
    struct
    {
        int __lock;
        unsigned int __futex;
        __extension__ unsigned long long int __total_seq;
        __extension__ unsigned long long int __wakeup_seq;
        __extension__ unsigned long long int __woken_seq;
        void *__mutex;
        unsigned int __nwaiters;
        unsigned int __broadcast_seq;
    } __data;
    char __size[48];
    __extension__ long long int __align;
} pthread_cond_t;

条件变量的静态初始化

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(1)pthread_cont_init(3)
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);

功能:
  主要用于初始化指定的条件变量;

参数:
  第一个参数:结构体类型的指针,存放要初始化的条件变量;
  第二个参数:结构体类型的指针,指定条件变量的属性,默认给NULL;

typedef union
{
    char __size[4];
    int __align;
} pthread_condattr_t;

返回值:
  success —- 0,error —- 非0;

(2)pthread_cond_signal(3)
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);

功能:
  启动一个线程,等待条件变量为真的线程;

参数:
  第一个参数:指定条件变量。在这个条件变量上等待的一个线程;

返回值:
  success —- 0,error —- 非0;

(3)pthread_cond_broadcast(3)
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);

功能:
  启动所有的线程,这些线程是等待条件变量为真的所有的线程;

参数:
  第一个参数:指定了条件变量,在这个条件变量上等待的所有线程;

返回值:
  success —- 0,error —- 非0;

(4)pthread_cond_wait(3)
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

功能:
  当条件变量不为真时,解开指定的mutex锁;等待至条件变量为真时,再给mutex加锁。

参数:
  第一个参数:指定要等待的条件变量;
  第二个参数:指定一个mutex锁;

返回值:
  success —- 0,error —- 非0;

(5)pthread_cond_timedwait(3)
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

功能:
  在指定时间内等待。超时返回错误。其他同上个函数。

参数:
  第一个参数:指定要等待的条件变量;
  第二个参数:指定一个mutex锁;
  第三个参数:指定了要等待的时间;

struct timespec
{
    __time_t tv_sec;             //__time_t = long int; 秒
    __syscall_slong_t tv_nsec;   //__syscall_slong_t = long int; 纳秒
};

返回值:
  success —- 0,error —- 非0;

(6)pthread_cond_destroy(3)
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);

功能:
  主要用于销毁指定的条件变量;

参数:
  第一个参数:指定要销毁的条件变量;

返回值:
  success —- 0,error —- 非0;

线程的实现:LinuxThreads:2.4、NPTL:2.6

LFS(Linux from Scratch)是一种从网上直接下载源码,从头编译LINUX的安装方式。

2.3 信号量

  信号量是指有多个相同的资源,多个线程竞争多个资源。在可用资源数减为0的情况下,线程等待。线程获取一个资源,可用资源数减1.当线程释放一个资源的时候,可用资源数加1。既能应用于多线程,又能应用于多进程。

信号量的类型是:sem_t

typedef union
{
    char __size[32];
    long int __align;
} sem_t;
(1)sem_init(3)
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
/* Link with -pthread. */

功能:
  初始化一个匿名的信号量;

参数:
  第一个参数:指定要初始化的信号量变量的地址;
  第二个参数:0 —- 多线程、非0 —- 多进程
  第三个参数:指定了信号量的初始化,信号量提供的资源数;

(2)sem_destroy(3)
#include <semaphore.h>
int sem_destroy(sem_t *sem);
/* Link with -pthread. */

功能:
  主要用于销毁一个指定的匿名信号量;

参数:
  第一个参数:指定要销毁的信号量;

(3) sem_post(3)
#include <semaphore.h>
int sem_post(sem_t *sem);
/* Link with -pthread. */

功能:
  主要用于解锁一个指定的信号量;

参数:
  第一个参数:指定要解锁的信号量。如果信号量可用资源数大于0,调用sem_wait等待的进程或线程这时候,被唤醒。

信号量的解锁是什么意思???
  increments信号量的值增加,可用资源数+1

(4)sem_wait(3)
#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
/* Link with -pthread. */

功能:
  主要用于锁定一个指定的信号量,此时信号量的可用资源数减1;

参数:
  第一个参数:指定要锁定的信号量。如果可用资源数大于0,立即返回。否则阻塞等待信号量的值大于0;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值