一、可重入函數的使用
線程函數儘量保持可重入性,不可重入函數會造成的臨界資源訪問的問題;
如:
/* 不可重入函數造成的臨界資源訪問問題 */
#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;