概述:
實現併發服務器一般都是父進程accept一個連接,然後fork一個子進程,該子進程處理與該連接對端的客戶之間的通信。但是fork是昂貴,耗資源和時間。而線程是輕量級線程,它的創建比進程的創建塊10-100倍。在同一進程內除了共享全局變量外還共享:
大多數數據;進程指令; 打開的文件; 信號處理函數信號處置; 當前工作目錄;用戶ID和組ID
不過每個線程有各自的資源:‘
線程ID; 寄存器集合了棧了errno; 信號掩碼; 優先級
基本線程函數:創建和終止
pthread_create函數
#include <pthread.h>
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg);
一個進程的每個線程都由一個線程ID標識。每個線程有很多屬性,比如優先級大小,初始棧大小,是否應該成爲一個守護線程等等
pthread_join函數
#include <pthread.h>
int pthread_join(pthread_t *tid, void **status);
該函數類似與waitpid
pthread_self函數
#include <pthread.h>
int pthread_self(void);
每個線程使用pthread_self獲得自身的線程ID
pthread_detach函數
#include <pthread.h>
int pthread_detach(pthread_t tid);
一個線程或者是可匯合的,或者是脫離的。當一個可匯合的線程終止時,它的線程ID和退出狀態將留存到另一個線程對它調用pthread_join。脫離的線程像守護線程,當他們終止時,所有相關資源都被釋放.
pthread_exit函數
#include <pthread.h>
int pthread_exit(void *status);
結束一個線程
互斥鎖的使用
多線程程序的經典問題:多個線程同時修改一個共享變量(如全局變量)
#include <pthread.h>
#include <stdio.h>
int counter;
void *doit(void*);
int main(int argc, char **argv)
{
pthread_t tidA, tidB;
pthread_create(&tidA, NULL, &doit, NULL);
pthread_create(&tidB, NULL, &doit, NULL);
pthread_join(tidA, NULL);
pthread_join(tidB, NULL);
return 0;
}
void *doit(void * arg)
{
int i, val;
for(i=0; i<10; i++)
{
val = counter;
printf("counter is %d\n", val+1);
counter = val+1;
}
return NULL;
}
上面程序的運行結果並不是我們想要的結果,因爲線程的運行是併發運行的,也就是說counter值的修改的結果是不定的,以下爲運行結果
所以我們應該引入同步機制,首先使用互斥量實現
#include <pthread.h>
#include <stdio.h>
int counter;
pthread_mutex_t counter_mutex;
void *doit(void*);
int main(int argc, char **argv)
{
pthread_t tidA, tidB;
pthread_create(&tidA, NULL, &doit, NULL);
pthread_create(&tidB, NULL, &doit, NULL);
pthread_join(tidA, NULL);
pthread_join(tidB, NULL);
return 0;
}
void *doit(void * arg)
{
int i, val;
for(i=0; i<10; i++)
{
pthread_mutex_lock(&counter_mutex);
val = counter;
printf("counter is %d\n", val+1);
counter = val+1;
pthread_mutex_unlock(&counter_mutex);
}
return NULL;
}
使用在對counter值進行修改之前進行上鎖操作,修改之後,進行解鎖操作