Linux線程方式
1. linux如何進行線程管理
方法一:PS
在ps命令中,「-T」選項可以開啟線程查看。下面的命令列出了由進程號為<pid>的進程創建的所有線程。
1.$ ps -T -p <pid>
「SID」欄表示線程ID,而「CMD」欄則顯示了線程名稱。
方法二: Top
top命令可以實時顯示各個線程情況。要在top輸出中開啟線程查看,請調用top命令的「-H」選項,該選項會列出所有Linux線程。在top運行時,你也可以通過按「H」鍵將線程查看模式切換為開或關。
1.$ top -H
要讓top輸出某個特定進程<pid>並檢查該進程內運行的線程狀況:
$ top -H -p <pid>
2. Linux 線程同步有哪些方法
一、互斥鎖(mutex)
1.
初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
靜態分配:pthread_mutex_t
mutex
=
PTHREAD_MUTEX_INITIALIZER;
動態分配:int
pthread_mutex_init(pthread_mutex_t
*mutex,
const
pthread_mutex_attr_t
*mutexattr);
2.
加鎖。對共享資源的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
int
pthread_mutex_lock(pthread_mutex
*mutex);
int
pthread_mutex_trylock(pthread_mutex_t
*mutex);
3.
解鎖。在完成了對共享資源的訪問後,要對互斥量進行解鎖。
int
pthread_mutex_unlock(pthread_mutex_t
*mutex);
4.
銷毀鎖。鎖在是使用完成後,需要進行銷毀以釋放資源。
int
pthread_mutex_destroy(pthread_mutex
*mutex);
二、條件變數(cond)
1.
初始化條件變數。
靜態態初始化,pthread_cond_t
cond
=
PTHREAD_COND_INITIALIER;
動態初始化,int
pthread_cond_init(pthread_cond_t
*cond,
pthread_condattr_t
*cond_attr);
2.
等待條件成立。釋放鎖,同時阻塞等待條件變數為真才行。timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)
int
pthread_cond_wait(pthread_cond_t
*cond,
pthread_mutex_t
*mutex);
int
pthread_cond_timewait(pthread_cond_t
*cond,pthread_mutex
*mutex,const
timespec
*abstime);
3.
激活條件變數。pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)
int
pthread_cond_signal(pthread_cond_t
*cond);
int
pthread_cond_broadcast(pthread_cond_t
*cond);
//解除所有線程的阻塞
4.
清除條件變數。無線程等待,否則返回EBUSY
int
pthread_cond_destroy(pthread_cond_t
*cond);
三、信號量(sem)
1.
信號量初始化。
int
sem_init
(sem_t
*sem
,
int
pshared,
unsigned
int
value);
這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux
只支持為0,即表示它是當前進程的局部信號量),然後給它一個初始值VALUE。
2.
等待信號量。給信號量減1,然後等待直到信號量的值大於0。
int
sem_wait(sem_t
*sem);
3.
釋放信號量。信號量值加1。並通知其他等待線程。
int
sem_post(sem_t
*sem);
4.
銷毀信號量。我們用完信號量後都它進行清理。歸還佔有的一切資源。
int
sem_destroy(sem_t
*sem);
3. 有人能教下我有關linux裡面線程的知識嗎
.線程的基本介紹
(1)線程的概述
線程與進程類似,也允許應用程序並發執行多個任務的一種機制。一個進程可以包含多個線程,同一程序中的所有線程共享同一份全局內存區域,線程之間沒有真正意義的等級之分。同一個進程中的線程可以並發執行,如果處理器是多核的話線程也可以並行執行,如果一個線程因為等待I/O操作而阻塞,那麼其他線程依然可以繼續運行
(2)線程優於進程的方面
argv,environ
主線程棧
線程3的棧
線程2的棧
線程1的棧
共享函數庫共享的內存
堆
未初始化的數據段
初始化數據段
文本
.進程間的信息難以共享。由於除去只讀代碼段外,父子進程並未共享內存,因此必須採用一些進程間通訊,在進程之間交換信息
.調用fork()來創建進程代價相對較高
線程很好的解決了上述倆個問題
.線程之間能夠方便,快速的共享信息,只需將數據復制到共享(全局或堆)變數中即可
.創建線程比創建線程通常要快10甚至更多,線程創建之所以快,是因為fork創建進程時所需復制多個屬性,而在線程中,這些屬性是共享的。
(3)創建線程
啟動程序時,產生的進程只有單條線程,我們稱之為主線程
#include<pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start)(void *),void *arg);12
新線程通過調用帶有arg的函數開始執行,調用pthread_create()的線程會繼續執行該調用之後的語句。
(4)終止線程
可以以如下方式終止線程的運行
.線程調用pthread_exit()
.線程start函數執行return語句並返回指定值
.調用pthread_cancel()取消線程
.任意線程調用了exit(),或者主線程執行了return語句,都會導致進程中的所有線程立即終止
pthread_exit()函數可以終止線程,且其返回值可由另一線程通過調用pthread_join()獲得
#include<pthread.h>void pthread_exit(void *retval);12
調用pthread_exit()相當於在線程的start函數中執行return,不同之處在於,pthread_exit()可以在任何地方調用,參數retval指定了線程的返回值
(5)獲取線程ID
#include<pthread.h>pthread_t pthread_self(void);12
線程ID在應用程序中主要有如下用途
.不同的pthreads函數利用線程ID來標識要操作目標線程。
.在具體的應用程序中,以特定線程的線程ID作為動態數據結構的標簽,這頗有用處,既可用來識別某個數據結構的創建者或屬主線程,又可確定隨後對該數據結構執行操作的具體線程
函數pthread_equal()可檢查倆個線程的ID是否相同
#include<pthread.h>int pthread_equal(pthread_t t1,pthread_t t2);//如果相同返回非0值,否則返回0123
(6)連接已終止的線程
函數pthread_join()等待由thread表識的線程終止
#include<pthread.h>int pthread_join(pthread_t thread,void **retval);//返回0調用成功,否則失敗123
如果pthread_join()傳入一個之前已然連接過的線程ID,將會導致無法預知的行為,當相同線程ID在參與一次連接後恰好為另一新建線程所重用,再度連接的可能就是這個新線程
若線程未分離,則就應該使用pthread_join()來連接線程,否則會產生僵屍線程
pthrea_join()函數的要點
.線程之間的關系是對等的,所以任意線程都可以調用pthread_join()來連接其他線程
.pthread_join()無法針對任意線程,只能連接單個線程
(6)線程的分離
默認情況下線程都是可連接的,但有時候,我們並不關心線程退出的狀態,我們可以調用pthread_detach()並向thread參數傳入指定線程的的標識符,將該線程標記為處於分離狀態
#include<pthread.h>int pthread_detach(pthread_t thread);//返回0成功,否則失敗123
一旦線程處於分離狀態,就不能在使用pthread_join()來獲取其狀態,也無法使其重返可連接狀態
(7)在應用程序中如何來選擇進程還是線程
.線程之間共享數據很簡單,進程間的數據共享需要更多的投入
.創建線程要比創建進程塊很多
.多線程編程時,需要確保調用線程安全的函數
.某個線程中的bug可能會危害進程中所有線程
.每個線程都在徵用宿主進程中有限的虛擬地址空間
.在多線程應用中,需要小心使用信號
.除了數據,線程還可以共享文件描述符,信號處置,當前工作目錄,以及用戶ID和組ID
線程的同步
(1)保護共享變數訪問:互斥量
線程的主要優勢在於能夠通過全局變數來共享信息,不過這種共享是有代價的。必須確保多個線程修改同一變數時,不會有其他線程也正在修改此變數,為避免線程更新時共享變數時所出現的問題,必須使用互斥量來確保同時僅有一個線程可以訪問某項共享資源
(2)靜態分配的互斥鎖
互斥鎖既可以像靜態變數那樣分配,也可以在運行時動態分配,互斥量屬於pthread_mutex_t類型的變數,在使用之前必須對其初始化。對於靜態分配的互斥量而言,可如下例所示,將PTHREAD_MUTEX_INITIALIZER賦給互斥量
pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;1
1.加鎖和解鎖互斥量
初始化之後,互斥量處於未鎖定狀態。函數pthread_mutex_lock()可以鎖定某一互斥量
而函數pthread_mutex_unlock()則可以將一個互斥量解鎖
#include<pthread.h>int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);//返回0成功,其他失敗1234
要鎖定互斥量,在調用pthread_mutex_lock()時需要指定互斥量,如果互斥量當前處於未鎖定狀態,則該調用將會立即返回,如果該互斥量已被其他線程鎖定,那麼該調用將會阻塞,直至互斥量被解鎖
函數pthread_mutex_unlock()將解鎖之前已遭調用線程鎖定的互斥量
2.互斥量的性能
通常情況下,線程會花費更多的時間去做其他工作,對互斥量的加鎖解鎖相對要少的多,因此使用互斥量對大部分程序來說性能並無顯著的影響
3.互斥量的死鎖
當一個線程需要同時訪問多個共享資源時,沒個資源由不同的互斥索管理。當超過一個線程加鎖同一組互斥量時,就有可能發生死鎖。如下圖所示
線程A
1.pthread_mutex_lock(mutex1);
2.pthread_mutex_lock(mutex2);
線程2
1.pthread_mutex_lock(mutex2);
2.pthread_mutex_lock(mutex1);
每個線程都成功的鎖住一個互斥量,接著試圖對以為另一線程鎖定的互斥量加鎖,就會一直等下去
要避免此類死鎖問題,最簡單的就是定義互斥量的層級關系
4. Linux線程的幾種結束方式
Linux線程的幾種結束方式
Linux創建線程使用
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
1
2
Linux線程的幾種結束方式:
調用pthread_exit(exit_code),exit_code為線程退出的狀態代碼。同一進程下的其他線程可以通過pthread_join(exit_code)來使用。
函數start_routine使用return返回,與調用pthread_exit()作用相同。
線程被取消pthread_cancel()。
同一進程中的其他線程調用了exit(),,或者主線程從main函數返回。
5. linux的線程同步方式有哪些
三種同步方式:1、互斥鎖(mutex)、2、條件同步(cond)、3、信號量(semphore).
如果還想深入:可以參考http://blog.csdn.net/zsf8701/article/details/7844316。
6. linux系統中線程同步實現機制有哪些
LinuxThread的線程機制
LinuxThreads是目前Linux平台上使用最為廣泛的線程庫,由Xavier Leroy ([email protected]) 負責開發完成,並已綁定在GLIBC中發行。它所實現的就是基於核心輕量級進程的"一對一"線程模型,一個線程實體對應一個核心輕量級進程,而線程之間的 管理在核外函數庫中實現。
1.線程描述數據結構及實現限制
LinuxThreads定義了一個struct _pthread_descr_struct數據結構來描述線程,並使用全局數組變數 __pthread_handles來描述和引用進程所轄線程。在__pthread_handles中的前兩項,LinuxThreads定義了兩個全 局的系統線程:__pthread_initial_thread和__pthread_manager_thread,並用 __pthread_main_thread表徵__pthread_manager_thread的父線程(初始為 __pthread_initial_thread)。
struct _pthread_descr_struct是一個雙環鏈表結構,__pthread_manager_thread所在的鏈表僅包括它 一個元素,實際上,__pthread_manager_thread是一個特殊線程,LinuxThreads僅使用了其中的errno、p_pid、 p_priority等三個域。而__pthread_main_thread所在的鏈則將進程中所有用戶線程串在了一起。經過一系列 pthread_create()之後形成的__pthread_handles數組將如下圖所示:
圖2 __pthread_handles數組結構
新創建的線程將首先在__pthread_handles數組中占據一項,然後通過數據結構中的鏈指針連入以__pthread_main_thread為首指針的鏈表中。這個鏈表的使用在介紹線程的創建和釋放的時候將提到。
LinuxThreads遵循POSIX1003.1c標准,其中對線程庫的實現進行了一些范圍限制,比如進程最大線程數,線程私有數據區大小等等。在 LinuxThreads的實現中,基本遵循這些限制,但也進行了一定的改動,改動的趨勢是放鬆或者說擴大這些限制,使編程更加方便。這些限定宏主要集中 在sysdeps/unix/sysv/linux/bits/local_lim.h(不同平台使用的文件位置不同)中,包括如下幾個:
每進程的私有數據key數,POSIX定義_POSIX_THREAD_KEYS_MAX為128,LinuxThreads使用 PTHREAD_KEYS_MAX,1024;私有數據釋放時允許執行的操作數,LinuxThreads與POSIX一致,定義 PTHREAD_DESTRUCTOR_ITERATIONS為4;每進程的線程數,POSIX定義為64,LinuxThreads增大到1024 (PTHREAD_THREADS_MAX);線程運行棧最小空間大小,POSIX未指定,LinuxThreads使用 PTHREAD_STACK_MIN,16384(位元組)。
2.管理線程
"一對一"模型的好處之一是線程的調度由核心完成了,而其他諸如線程取消、線程間的同步等工作,都是在核外線程庫中完成的。在LinuxThreads 中,專門為每一個進程構造了一個管理線程,負責處理線程相關的管理工作。當進程第一次調用pthread_create()創建一個線程的時候就會創建 (__clone())並啟動管理線程。
在一個進程空間內,管理線程與其他線程之間通過一對"管理管道(manager_pipe[2])"來通訊,該管道在創建管理線程之前創建,在成功啟動 了管理線程之後,管理管道的讀端和寫端分別賦給兩個全局變數__pthread_manager_reader和 __pthread_manager_request,之後,每個用戶線程都通過__pthread_manager_request向管理線程發請求, 但管理線程本身並沒有直接使用__pthread_manager_reader,管道的讀端(manager_pipe[0])是作為__clone ()的參數之一傳給管理線程的,管理線程的工作主要就是監聽管道讀端,並對從中取出的請求作出反應。
創建管理線程的流程如下所示:
(全局變數pthread_manager_request初值為-1)
圖3 創建管理線程的流程
初始化結束後,在__pthread_manager_thread中記錄了輕量級進程號以及核外分配和管理的線程id, 2*PTHREAD_THREADS_MAX+1這個數值不會與任何常規用戶線程id沖突。管理線程作為pthread_create()的調用者線程的 子線程運行,而pthread_create()所創建的那個用戶線程則是由管理線程來調用clone()創建,因此實際上是管理線程的子線程。(此處子 線程的概念應該當作子進程來理解。)
__pthread_manager()就是管理線程的主循環所在,在進行一系列初始化工作後,進入while(1)循環。在循環中,線程以2秒為 timeout查詢(__poll())管理管道的讀端。在處理請求前,檢查其父線程(也就是創建manager的主線程)是否已退出,如果已退出就退出 整個進程。如果有退出的子線程需要清理,則調用pthread_reap_children()清理。
然後才是讀取管道中的請求,根據請求類型執行相應操作(switch-case)。具體的請求處理,源碼中比較清楚,這里就不贅述了。
3.線程棧
在LinuxThreads中,管理線程的棧和用戶線程的棧是分離的,管理線程在進程堆中通過malloc()分配一個THREAD_MANAGER_STACK_SIZE位元組的區域作為自己的運行棧。
用戶線程的棧分配辦法隨著體系結構的不同而不同,主要根據兩個宏定義來區分,一個是NEED_SEPARATE_REGISTER_STACK,這個屬 性僅在IA64平台上使用;另一個是FLOATING_STACK宏,在i386等少數平台上使用,此時用戶線程棧由系統決定具體位置並提供保護。與此同 時,用戶還可以通過線程屬性結構來指定使用用戶自定義的棧。因篇幅所限,這里只能分析i386平台所使用的兩種棧組織方式:FLOATING_STACK 方式和用戶自定義方式。
在FLOATING_STACK方式下,LinuxThreads利用mmap()從內核空間中分配8MB空間(i386系統預設的最大棧空間大小,如 果有運行限制(rlimit),則按照運行限制設置),使用mprotect()設置其中第一頁為非訪問區。該8M空間的功能分配如下圖:
圖4 棧結構示意
低地址被保護的頁面用來監測棧溢出。
對於用戶指定的棧,在按照指針對界後,設置線程棧頂,並計算出棧底,不做保護,正確性由用戶自己保證。
不論哪種組織方式,線程描述結構總是位於棧頂緊鄰堆棧的位置。
4.線程id和進程id
每個LinuxThreads線程都同時具有線程id和進程id,其中進程id就是內核所維護的進程號,而線程id則由LinuxThreads分配和維護。
7. Linux多進程和線程同步的幾種方式
Linux 線程同步的三種方法
線程的最大特點是資源的共享性,但資源共享中的同步問題是多線程編程的難點。linux下提供了多種方式來處理線程同步,最常用的是互斥鎖、條件變數和信號量。
一、互斥鎖(mutex)
通過鎖機制實現線程間的同步。
初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
靜態分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
動態分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
加鎖。對共享資源的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
int pthread_mutex_lock(pthread_mutex *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
解鎖。在完成了對共享資源的訪問後,要對互斥量進行解鎖。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
銷毀鎖。鎖在是使用完成後,需要進行銷毀以釋放資源。
int pthread_mutex_destroy(pthread_mutex *mutex);
[csharp] view plain
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include "iostream"
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tmp;
void* thread(void *arg)
{
cout << "thread id is " << pthread_self() << endl;
pthread_mutex_lock(&mutex);
tmp = 12;
cout << "Now a is " << tmp << endl;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t id;
cout << "main thread id is " << pthread_self() << endl;
tmp = 3;
cout << "In main func tmp = " << tmp << endl;
if (!pthread_create(&id, NULL, thread, NULL))
{
cout << "Create thread success!" << endl;
}
else
{
cout << "Create thread failed!" << endl;
}
pthread_join(id, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
//編譯:g++ -o thread testthread.cpp -lpthread
二、條件變數(cond)
互斥鎖不同,條件變數是用來等待而不是用來上鎖的。條件變數用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變數和互斥鎖同時使用。條件變數分為兩部分: 條件和變數。條件本身是由互斥量保護的。線程在改變條件狀態前先要鎖住互斥量。條件變數使我們可以睡眠等待某種條件出現。條件變數是利用線程間共享的全局變數進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變數的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,並釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件變數,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變數可以被用來實現這兩進程間的線程同步。
初始化條件變數。
靜態態初始化,pthread_cond_t cond = PTHREAD_COND_INITIALIER;
動態初始化,int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
等待條件成立。釋放鎖,同時阻塞等待條件變數為真才行。timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
激活條件變數。pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有線程的阻塞
清除條件變數。無線程等待,否則返回EBUSY
int pthread_cond_destroy(pthread_cond_t *cond);
[cpp] view plain
#include <stdio.h>
#include <pthread.h>
#include "stdlib.h"
#include "unistd.h"
pthread_mutex_t mutex;
pthread_cond_t cond;
void hander(void *arg)
{
free(arg);
(void)pthread_mutex_unlock(&mutex);
}
void *thread1(void *arg)
{
pthread_cleanup_push(hander, &mutex);
while(1)
{
printf("thread1 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread1 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(4);
}
pthread_cleanup_pop(0);
}
void *thread2(void *arg)
{
while(1)
{
printf("thread2 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread2 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t thid1,thid2;
printf("condition variable study!\n");
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thid1, NULL, thread1, NULL);
pthread_create(&thid2, NULL, thread2, NULL);
sleep(1);
do
{
pthread_cond_signal(&cond);
}while(1);
sleep(20);
pthread_exit(0);
return 0;
}
[cpp] view plain
#include <pthread.h>
#include <unistd.h>
#include "stdio.h"
#include "stdlib.h"
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct node
{
int n_number;
struct node *n_next;
}*head = NULL;
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread./n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
struct node *p = NULL;
pthread_cleanup_push(cleanup_handler, p);
while (1)
{
//這個mutex主要是用來保證pthread_cond_wait的並發性
pthread_mutex_lock(&mtx);
while (head == NULL)
{
//這個while要特別說明一下,單個pthread_cond_wait功能很完善,為何
//這里要有一個while (head == NULL)呢?因為pthread_cond_wait里的線
//程可能會被意外喚醒,如果這個時候head != NULL,則不是我們想要的情況。
//這個時候,應該讓線程繼續進入pthread_cond_wait
// pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,
//然後阻塞在等待對列里休眠,直到再次被喚醒(大多數情況下是等待的條件成立
//而被喚醒,喚醒後,該進程會先鎖定先pthread_mutex_lock(&mtx);,再讀取資源
//用這個流程是比較清楚的
pthread_cond_wait(&cond, &mtx);
p = head;
head = head->n_next;
printf("Got %d from front of queue/n", p->n_number);
free(p);
}
pthread_mutex_unlock(&mtx); //臨界區數據操作完畢,釋放互斥鎖
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
//子線程會一直等待資源,類似生產者和消費者,但是這里的消費者可以是多個消費者,而
//不僅僅支持普通的單個消費者,這個模型雖然簡單,但是很強大
pthread_create(&tid, NULL, thread_func, NULL);
sleep(1);
for (i = 0; i < 10; i++)
{
p = (struct node*)malloc(sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx); //需要操作head這個臨界資源,先加鎖,
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx); //解鎖
sleep(1);
}
printf("thread 1 wanna end the line.So cancel thread 2./n");
//關於pthread_cancel,有一點額外的說明,它是從外部終止子線程,子線程會在最近的取消點,退出
//線程,而在我們的代碼里,最近的取消點肯定就是pthread_cond_wait()了。
pthread_cancel(tid);
pthread_join(tid, NULL);
printf("All done -- exiting/n");
return 0;
}
三、信號量(sem)
如同進程一樣,線程也可以通過信號量來實現通信,雖然是輕量級的。信號量函數的名字都以"sem_"打頭。線程使用的基本信號量函數有四個。
信號量初始化。
int sem_init (sem_t *sem , int pshared, unsigned int value);
這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux 只支持為0,即表示它是當前進程的局部信號量),然後給它一個初始值VALUE。
等待信號量。給信號量減1,然後等待直到信號量的值大於0。
int sem_wait(sem_t *sem);
釋放信號量。信號量值加1。並通知其他等待線程。
int sem_post(sem_t *sem);
銷毀信號量。我們用完信號量後都它進行清理。歸還佔有的一切資源。
int sem_destroy(sem_t *sem);
[cpp] view plain
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#define return_if_fail(p) if((p) == 0){printf ("[%s]:func error!/n", __func__);return;}
typedef struct _PrivInfo
{
sem_t s1;
sem_t s2;
time_t end_time;
}PrivInfo;
static void info_init (PrivInfo* thiz);
static void info_destroy (PrivInfo* thiz);
static void* pthread_func_1 (PrivInfo* thiz);
static void* pthread_func_2 (PrivInfo* thiz);
int main (int argc, char** argv)
{
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
int ret = 0;
PrivInfo* thiz = NULL;
thiz = (PrivInfo* )malloc (sizeof (PrivInfo));
if (thiz == NULL)
{
printf ("[%s]: Failed to malloc priv./n");
return -1;
}
info_init (thiz);
ret = pthread_create (&pt_1, NULL, (void*)pthread_func_1, thiz);
if (ret != 0)
{
perror ("pthread_1_create:");
}
ret = pthread_create (&pt_2, NULL, (void*)pthread_func_2, thiz);
if (ret != 0)
{
perror ("pthread_2_create:");
}
pthread_join (pt_1, NULL);
pthread_join (pt_2, NULL);
info_destroy (thiz);
return 0;
}
static void info_init (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
thiz->end_time = time(NULL) + 10;
sem_init (&thiz->s1, 0, 1);
sem_init (&thiz->s2, 0, 0);
return;
}
static void info_destroy (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
sem_destroy (&thiz->s1);
sem_destroy (&thiz->s2);
free (thiz);
thiz = NULL;
return;
}
static void* pthread_func_1 (PrivInfo* thiz)
{
return_if_fail(thiz != NULL);
while (time(NULL) < thiz->end_time)
{
sem_wait (&thiz->s2);
printf ("pthread1: pthread1 get the lock./n");
sem_post (&thiz->s1);
printf ("pthread1: pthread1 unlock/n");
sleep (1);
}
return;
}
static void* pthread_func_2 (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
while (time (NULL) < thiz->end_time)
{
sem_wait (&thiz->s1);
printf ("pthread2: pthread2 get the unlock./n");
sem_post (&thiz->s2);
printf ("pthread2: pthread2 unlock./n");
sleep (1);
}
return;
}
8. 如何在Linux中查看進程的多線程
方法/步驟
問題: 我的程序在其內部創建並執行了多個線程,我怎樣才能在該程序創建線程後監控其中單個線程?我想要看到帶有它們名稱的單個線程詳細情況(如,CPU/內存使用率)。
線程是現代操作系統上進行並行執行的一個流行的編程方面的抽象概念。當一個程序內有多個線程被叉分出用以執行多個流時,這些線程就會在它們之間共享 特定的資源(如,內存地址空間、打開的文件),以使叉分開銷最小化,並避免大量高成本的IPC(進程間通信)通道。這些功能讓線程在並發執行時成為一個高 效的機制。
在Linux中,程序中創建的線程(也稱為輕量級進程,LWP)會具有和程序的PID相同的「線程組ID」。然後,各個線程會獲得其自身的線程 ID(TID)。對於Linux內核調度器而言,線程不過是恰好共享特定資源的標準的進程而已。經典的命令行工具,如ps或top,都可以用來顯示線程級 別的信息,只是默認情況下它們顯示進程級別的信息。
這里提供了在Linux上顯示某個進程的線程的幾種方式。
方法一:PS
在ps命令中,「-T」選項可以開啟線程查看。下面的命令列出了由進程號為<pid>的進程創建的所有線程。
1.$ ps -T -p <pid>
「SID」欄表示線程ID,而「CMD」欄則顯示了線程名稱。
方法二: Top
top命令可以實時顯示各個線程情況。要在top輸出中開啟線程查看,請調用top命令的「-H」選項,該選項會列出所有Linux線程。在top運行時,你也可以通過按「H」鍵將線程查看模式切換為開或關。
1.$ top -H
要讓top輸出某個特定進程<pid>並檢查該進程內運行的線程狀況:
$ top -H -p <pid>
方法三: Htop
一個對用戶更加友好的方式是,通過htop查看單個進程的線程,它是一個基於ncurses的交互進程查看器。該程序允許你在樹狀視圖中監控單個獨立線程。
要在htop中啟用線程查看,請開啟htop,然後按<F2>來進入htop的設置菜單。選擇「設置」欄下面的「顯示選項」,然後開啟「樹狀視圖」和「顯示自定義線程名」選項。按<F10>退出設置。
5
現在,你就會看到下面這樣單個進程的線程視圖。
9. linux操作系統多進程和多線程的區別
進程:運行中的程序,-->執行過程稱之為進程。
線程:線程是輕量級的進程,是進程中的一條執行序列,一個進程至少有一條線程。
多線程優點:①無需跨進程邊界;②程序邏輯和控制方式簡單;③所有線程可以直接共享內存和變數;④線程方式消耗的總資源比進程少。
多進程優點:①每個進程相互獨立,不影響主程序的穩定性,子進程崩潰沒關系;②通過增加CPU就可以容易擴充性能;③可以盡量減少線程加鎖/解鎖的影響,極大提高性能。
多線程缺點:①每條線程與主程序共用地址空間,大小受限;②線程之間的同步和加鎖比較麻煩;③一個線程的崩潰可能影響到整個程序的穩定性;④到達一定的線程數之後,即使在增加CPU也無法提高性能。
多進程缺點:①邏輯控制復雜,需要和主程序交互;②需要跨進程邊界,如果有大數據傳輸,不適合;③多進程調度開銷比較大。
Linux系統中多進程和多線程的區別是什麼?
1、多進程中數據共享復雜、同步簡單;而多線程中數據共享簡單、同步復雜。
2、多進程佔用內存多、切換復雜、速度慢、CPU利用率低;而多線程佔用內存少、切換簡單、CPU利用率高。
3、多進程的編程簡單、調試簡單;而多線程的編程復雜、調試復雜。
10. linux裡面,進程與線程到底有什麼本質的區別
線程:是進程中執行的一條路徑,是系統調度的最小單位。
進程:是正在運行的程序,是系統分配資源的最小單位。
線程與進程關系
1.一個進程可以有多個線程,一個線程只能屬於一個進程。
2.同一個進程下的所有線程共享該進程下的所有資源。
3.真正在處理機上運行的是線程,不是進程,線程是進程內的一個執行單元,是進程內的可調度實體。
Linux線程與進程區別
進程:
優點:多進程可以同時利用多個CPU,能夠同時進行多個操作。
缺點:耗費資源(創建一個進程重新開辟內存空間)。
進程不是越多越好,一般進程個數等於cpu個數。
線程:
優點:共享內存,尤其是進行IO操作(網路、磁碟)的時候(IO操作很少用cpu),可以使用多線程執行並發操作。
缺點:搶占資源。