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;

發佈了50 篇原創文章 · 獲贊 48 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章