A. 淺談linux多線程編程和Windows多線程編程的異同
轉載自fychit創意空間 很早以前就想寫寫linux下多線程編程和windows下的多線程編程了,但是每當寫時又不知道從哪個地方寫起,怎樣把自己知道的東西都寫出來,下面我就談談linux多線程及線程同步,並將它和windows的多線程進行比較,看看他們之間有什麼相同點和不同的地方。
其實最開始我是搞windows下編程的,包括windows編程,windows 驅動,包括usb驅動,ndis驅動,pci驅動,1394驅動等等,同時也一條龍服務,做windows下的應用程序開發,後面慢慢的我又對linux開發產生比較深的興趣和愛好,就轉到搞linux開發了。在接下來的我還會寫一些博客,主要是寫linux編程和windows編程的區別吧,現在想寫的是linux下usb驅動和windows下usb驅動開發的區別,這些都是後話,等我將linux多線程和windows多線程講解完後,我再寫一篇usb驅動,談談windows 和linux usb驅動的東東。好了,言歸正傳。開始將多線程了。
首先我們講講為什麼要採用多線程編程,其實並不是所有的程序都必須採用多線程,有些時候採用多線程,性能還沒有單線程好。所以我們要搞清楚,什麼時候採用多線程。採用多線程的好處如下:
(1)因為多線程彼此之間採用相同的地址空間,共享大部分的數據,這樣和多進程相比,代價比較節儉,因為多進程的話,啟動新的進程必須分配給它獨立的地址空間,這樣需要數據表來維護代碼段,數據段和堆棧段等等。
(2)多線程和多進程相比,一個明顯的優點就是線程之間的通信了,對不同進程來說,它們具有獨立的數據空間,要進行數據的傳遞只能通過通信的方式進行,這種方式不僅費時,而且很不方便。但是對於多線程就不一樣了。他們之間可以直接共享數據,比如最簡單的方式就是共享全局變數。但是共享全部變數也要注意哦,呵呵,必須注意同步,不然後果你知道的。呵呵。
(3)在多cpu的情況下,不同的線程可以運行不同的cpu下,這樣就完全並行了。
反正我覺得在這種情況下,採用多線程比較理想。比如說你要做一個任務分2個步驟,你為提高工作效率,你可以多線程技術,開辟2個線程,第一個線程就做第一步的工作,第2個線程就做第2步的工作。但是你這個時候要注意同步了。因為只有第一步做完才能做第2步的工作。這時,我們可以採用同步技術進行線程之間的通信。
針對這種情況,我們首先講講多線程之間的通信,在windows平台下,多線程之間通信採用的方法主要有:
(1)共享全局變數,這種方法是最容易想到的,呵呵,那就首先講講吧,比如說吧,上面的問題,第一步要向第2步傳遞收據,我們可以之間共享全局變數,讓兩個線程之間傳遞數據,這時主要考慮的就是同步了,因為你後面的線程在對數據進行操作的時候,你第一個線程又改變了數據的內容,你不同步保護,後果很嚴重的。你也知道,這種情況就是讀臟數據了。在這種情況下,我們最容易想到的同步方法就是設置一個bool flag了,比如說在第2個線程還沒有用完數據前,第一個線程不能寫入。有時在2個線程所需的時間不相同的時候,怎樣達到最大效率的同步,就比較麻煩了。咱們可以多開幾個緩沖區進行操作。就像生產者消費者一樣了。如果是2個線程一直在跑的,由於時間不一致,緩沖區遲早會溢出的。在這種情況下就要考慮了,是不讓數據寫入還是讓數據覆蓋掉老的數據,這時候就要具體問題具體分析了。就此打住,呵呵。就是用bool變數控制同步,linux 和windows是一樣的。
既然講道了這里,就再講講其它同步的方法。同樣 針對上面的這個問題,共享全局變數同步問題。除了採用bool變數外,最容易想到的方法就是互斥量了。呵呵,也就是傳說中的加鎖了。windows下加鎖和linux下加鎖是類似的。採用互斥量進行同步,要想進入那段代碼,就先必須獲得互斥量。
linux上互斥量的函數是:
windows下互斥量的函數有:createmutex 創建一個互斥量,然後就是獲得互斥量waitforsingleobject函數,用完了就釋放互斥量ReleaseMutex(hMutex),當減到0的時候 內核會才會釋放其對象。下面是windows下與互斥的幾個函數原型。
HANDLE WINAPI CreateMutex(
__in LPSECURITY_ATTRIBUTES lpMutexAttributes,
__in BOOL bInitialOwner,
__in LPCTSTR lpName
);
可以可用來創建一個有名或無名的互斥量對象
第一參數 可以指向一個結構體SECURITY_ATTRIBUTES一般可以設為null;
第二參數 指當時的函數是不是感應感應狀態 FALSE為當前擁有者不會創建互斥
第三參數 指明是否是有名的互斥對象 如果是無名 用null就好。
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
);
第一個是 創建的互斥對象的句柄。第二個是 表示將在多少時間之後返回 如果設為宏INFINITE 則不會返回 直到用戶自己定義返回。
對於linux操作系統,互斥也是類似的,只是函數不同罷了。在linux下,和互斥相關的幾個函數也要閃亮登場了。
pthread_mutex_init函數:初始化一個互斥鎖;
pthread_mutex_destroy函數:注銷一個互斥鎖;
pthread_mutex_lock函數:加鎖,如果不成功,阻塞等待;
pthread_mutex_unlock函數:解鎖;
pthread_mutex_trylock函數:測試加鎖,如果不成功就立即返回,錯誤碼為EBUSY;
至於這些函數的用法,google上一搜,就出來了,呵呵,在這里不多講了。windows下還有一個可以用來保護數據的方法,也是線程同步的方式
就是臨界區了。臨界區和互斥類似。它們之間的區別是,臨界區速度快,但是它只能用來同步同一個進程內的多個線程。臨界區的獲取和釋放函數如下:
EnterCriticalSection() 進入臨界區; LeaveCriticalSection()離開臨界區。 對於多線程共享內存的東東就講到這里了。
(2)採用消息機制進行多線程通信和同步,windows下面的的消息機制的函數用的多的就是postmessage了。Linux下的消息機制,我用的較少,就不在這里說了,如果誰熟悉的,也告訴我,呵呵。
(3)windows下的另外一種線程通信方法就是事件和信號量了。同樣針對我開始舉得例子,2個線程同步,他們之間傳遞信息,可以採用事件(Event)或信號量(Semaphore),比如第一個線程完成生產的數據後,就必須告訴第2個線程,他已經把數據准備好了,你可以來取走了。第2個線程就把數據取走。呵呵,這里可以採用消息機制,當第一個線程准備好數據後,就直接postmessage給第2個線程,按理說採用postmessage一個線程就可以搞定這個問題了。呵呵,不是重點,省略不講了。
對於linux,也有類似的方法,就是條件變數了,呵呵,這里windows和linux就有不同了。要特別講講才行。
對於windows,採用事件和信號量同步時候,都會使用waitforsingleobject進行等待的,這個函數的第一個參數是一個句柄,在這里可以是Event句柄,或Semaphore句柄,第2個參數就是等待的延遲,最終等多久,單位是ms,如果這個參數為INFINITE,那麼就是無限等待了。釋放信號量的函數為ReleaseSemaphore();釋放事件的函數為SetEvent。當然使用這些東西都要初始化的。這里就不講了。Msdn一搜,神馬都出來了,呵呵。神馬都是浮雲!
對於linux操作系統,是採用條件變數來實現類似的功能的。Linux的條件變數一般都是和互斥鎖一起使用的,主要的函數有:
pthread_mutex_lock ,
pthread_mutex_unlock,
pthread_cond_init
pthread_cond_signal
pthread_cond_wait
pthread_cond_timewait
B. 誰能推薦本講linux多線程編程的書籍
感覺書上面提到的多線程編程都比較偏理論,都主要是講線程的創建,退出,同步等一些情況,APUE講解的也比較好理解,另外推薦看一下linux下的一些開源代碼,比如pcsc-lite,它的主體構架就是多線程的,可以適當的參考一下它的框架。
C. Linux下如何實現shell多線程編程
程序代碼test.c共兩個線程,一個主線程,一個讀緩存區的線程:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char globe_buffer[100];
void *read_buffer_thread(void *arg); //這里先聲明一下讀緩存的線程,具體實現寫在後面了
int main()
{
int res,i;
pthread_t read_thread;
for(i=0;i<20;i++)
globe_buffer[i]=i;
printf("\nTest thread : write buffer finish\n");
sleep(3);\\這里的3秒是多餘,可以不要。
res = pthread_create(&read_thread, NULL, read_buffer_thread, NULL);
if (res != 0)
{
printf("Read Thread creat Error!");
exit(0);
}
sleep(1);
printf("waiting for read thread to finish...\n");
res = pthread_join(read_thread, NULL);
if (res != 0)
{
printf("read thread join failed!\n");
exit(0);
}
printf("read thread test OK, have fun!! exit ByeBye\n");
return 0;
}
void *read_buffer_thread(void *arg)
{
int i,x;
printf("Read buffer thread read data : \n");
for(i=0;i<20;i++)
{
x=globe_buffer[i];
printf("%d ",x);
globe_buffer[i]=0;//清空
}
printf("\nread over\n");
}
---------------------------------------------------------------------------------
以上程序編譯:
gcc -D_REENTRANT test.c -o test.o –lpthread
運行這個程序:
$ ./test.o:
D. Linux多線程編程時如何查看一個進程中的某
1。 使用top命令,具體用法是 top -H
加上這個選項,top的每一行就不是顯示一個進程,而是一個線程。
2。 使用ps命令,具體用法是 ps -xH
這樣可以查看所有存在的線程,也可以使用grep作進一步的過濾。
3。 使用ps命令,具體用法是 ps -mq PID
這樣可以看到指定的進程產生的線程數目。
更進一步,其實一些系統監控工具,在本質上也是讀取的系統產生的文件罷了。比如說進程這個事情,
看看這個目錄吧,/proc/5000/ 這裡面有你所有想要的。其實stat代表著當前的一些信息。
使用ps命令來查看進程的時候,進程狀態分別對應的含義如下:
D 不可中斷睡眠 (通常是在IO操作) 收到信號不喚醒和不可運行, 進程必須等待直到有中斷發生
R 正在運行或可運行(在運行隊列排隊中)
S 可中斷睡眠 (休眠中, 受阻, 在等待某個條件的形成或接受到信號)
T 已停止的 進程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信號後停止運行
W 正在換頁(2.6.內核之前有效)
X 死進程 (未開啟)
Z 僵屍進程 進程已終止, 但進程描述符存在, 直到父進程調用wait4()系統調用後釋放BSD風格的
< 高優先順序(not nice to other users)
N 低優先順序(nice to other users)
L 頁面鎖定在內存(實時和定製的IO)
s 一個信息頭
l 多線程(使用 CLONE_THREAD,像NPTL的pthreads的那樣)
+ 在前台進程組
E. Linux多線程編程
程序代碼test.c共兩個線程,一個主線程,一個讀緩存區的線程:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char globe_buffer[100];
void *read_buffer_thread(void *arg); //這里先聲明一下讀緩存的線程,具體實現寫在後面了
int main()
{
int res,i;
pthread_t read_thread;
for(i=0;i<20;i++)
globe_buffer[i]=i;
printf("\nTest thread : write buffer finish\n");
sleep(3);\\這里的3秒是多餘,可以不要。
res = pthread_create(&read_thread, NULL, read_buffer_thread, NULL);
if (res != 0)
{
printf("Read Thread creat Error!");
exit(0);
}
sleep(1);
printf("waiting for read thread to finish...\n");
res = pthread_join(read_thread, NULL);
if (res != 0)
{
printf("read thread join failed!\n");
exit(0);
}
printf("read thread test OK, have fun!! exit ByeBye\n");
return 0;
}
void *read_buffer_thread(void *arg)
{
int i,x;
printf("Read buffer thread read data : \n");
for(i=0;i<20;i++)
{
x=globe_buffer[i];
printf("%d ",x);
globe_buffer[i]=0;//清空
}
printf("\nread over\n");
}
---------------------------------------------------------------------------------
以上程序編譯:
gcc -D_REENTRANT test.c -o test.o –lpthread
運行這個程序:
$ ./test.o:
F. linux裡面線程編譯運行問題
#gcc a.c -o a #此句的-o a說明輸出目標文件為「a」;
#gcc -Wall-lpthread threadcreatetest.c #此句未註明輸出目標文件名,系統默認輸出為a.out,所以編譯之後執行./a.out文件。
如果上句也沒有指明「 -o a 」的話,輸出也是a.out,你可以試試
G. Linux 的多線程編程中,如何給線程發信號
不管是在進程還是線程,很多時候我們都會使用一些定時器之類的功能,這里就定時器在多線程的使用說一下。首先在linux編程中定時器函數有alarm()和setitimer(),alarm()可以提供一個基於秒的定時功能,而setitimer可以提供一個基於微妙的定時功能。
alarm()原型:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
這個函數在使用上很簡單,第一次調用這個函數的時候是設置定時器的初值,下一次調用是重新設置這個值,並會返回上一次定時的剩餘時間。
setitimer()原型:
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value,struct itimerval *ovalue);
這個函數使用起來稍微有點說法,首先是第一個參數which的值,這個參數設置timer的計時策略,which有三種狀態分別是:
ITIMER_REAL:使用系統時間來計數,時間為0時發出SIGALRM信號,這種定時能夠得到一個精準的定時,當然這個定時是相對的,因為到了微秒級別我們的處理器本身就不夠精確。
ITIMER_VIRTUAL:使用進程時間也就是進程分配到的時間片的時間來計數,時間為0是發出SIGVTALRM信號,這種定時顯然不夠准確,因為系統給進程分配時間片不由我們控制。
ITIMER_PROF:上面兩種情況都能夠觸發
第二個參數參數value涉及到兩個結構體:
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
在結構體itimerval中it_value是定時器當前的值,it_interval是當it_value的為0後重新填充的值。而timeval結構體中的兩個變數就簡單了一個是秒一個是微秒。
上面是這兩個定時函數的說明,這個函數使用本不是很難,可以說是很簡單,但是碰到具體的應用的時候可能就遇到問題了,在多進程編程中使用一般不會碰到什麼問題,這里說的這些問題主要體現在多線程編程中。比如下面這個程序:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
void sig_handler(int signo)
{
alarm(2);
printf("alarm signal\n");
}
void *pthread_func()
{
alarm(2);
while(1)
{
pause();
}
}
int main(int argc, char **argv)
{
pthread_t tid;
int retval;
signal(SIGALRM, sig_handler);
if((retval = pthread_create(&tid, NULL, pthread_func, NULL)) < 0)
{
perror("pthread_create");
exit(-1);
}
while(1)
{
printf("main thread\n");
sleep(10);
}
return 0;
}
這個程序的理想結果是:
main thread
alarm signal
alarm signal
alarm signal
alarm signal
alarm signal
main thread
可事實上並不是這樣的,它的結果是:
main pthread
alarm signal
main pthread
alarm signal
main pthread
H. linux系統下,c語言pthread多線程編程傳參問題
3個線程使用的都是同一個info
代碼 Info_t *info= (Info_t *)malloc(sizeof(Info_t));只創建了一個info
pthread_create(&threads[i],NULL,calMatrix,(void *)info); 三個線程使用的是同一個
我把你的代碼改了下:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
intmtc[3]={0};//resultmatrix
typedefstruct
{
intprank;
int*mta;
int*mtb;
}Info_t;
void*calMatrix(void*arg)
{
inti;
Info_t*info=(Info_t*)arg;
intprank=info->prank;
fprintf(stdout,"calMatrix:prankis%d ",prank);
for(i=0;i<3;i++)
mtc[prank]+=info->mta[i]*info->mtb[i];
returnNULL;
}
intmain(intargc,char**argv)
{
inti,j,k=0;
intmta[3][3];
intmtb[3]={1};
Info_t*info=(Info_t*)malloc(sizeof(Info_t)*3);
for(i=0;i<3;i++)
for(j=0;j<3;j++)
mta[i][j]=k++;
/*3threads*/
pthread_t*threads=(pthread_t*)malloc(sizeof(pthread_t)*3);
fprintf(stdout," ");fflush(stdout);
for(i=0;i<3;i++)
{
info[i].prank=i;
info[i].mta=mta[i];
info[i].mtb=mtb;
pthread_create(&threads[i],NULL,calMatrix,(void*)(&info[i]));
}
for(i=0;i<3;i++)
pthread_join(threads[i],NULL);
fprintf(stdout," ====thematrixresult==== ");
fflush(stdout);
for(i=0;i<3;i++)
{
fprintf(stdout,"mtc[%d]=%d ",i,mtc[i]);
fflush(stdout);
}
return0;
}
矩陣的計算我忘記了,你運行看看結果對不對
I. Linux多線程編程問題
暈,沒在 Linux下編過,盡管我的電腦有Linux系統