當前位置:首頁 » 操作系統 » Linux信號與線程

Linux信號與線程

發布時間: 2023-11-23 17:14:30

Ⅰ 麻煩解釋一下linux下進程和線程有什麼區別和聯系,linux下多線程和多進程通信的實現方法,請通俗解釋

兄弟看到你這么高的分我就找了些資料:也算是對昨天學的知識總結一下吧
一、先說概念不管是windows還是linux下的進程和線程概念都是一樣的,只是管理進程和線程的方式不一樣,這個是前提,到時候你可別問我windows下進程和線程啊。這個涉及到操作系統原理。下面給你解答。
說道進程不得不提作業這個名詞 ,我想兄弟你電腦里不會有一個程序吧對不?當你的系統啟動完畢後你看看你的任務管理器里是不是有很多進程呢?那麼多程序是怎麼調如內存呢?能理解嗎?這里要明白程序和進程的關系,程序是你磁碟上的一個文件,當你需要它時進入內存後才成為進程,好比QQ在磁碟上就是一個文件而已,只有進入了內存才成為進程,進程是活動的。QQ要掃描你文件啊,記錄你聊天記錄啊,偷偷上傳個啥東西什麼的你也不知道對不,他是活動的。這個能明白嗎?
再看作業,這個作業可不是你寫作業的那個作業啊。系統一看好傢伙你個QQ那麼大的傢伙你想一下子進入內存啊?沒門!慢慢來嘛,系統就把QQ程序分為好幾塊,這幾塊不能亂分的,要符合自然結構就是循環啦選擇啦這樣的結構,你把人家循環結構咔嚓截斷了,怎麼讓人家QQ運行啊?這就是作業要一塊一塊的進入內存,同時要為作業產生JCB(JOB CONTROL BLOCK)作業控制塊,你進入內存不能亂跑啊,要聽系統的話,你要是進入系統自己的內存。框一下,內存不能讀寫 對話框就出來了,嚴重點直接藍臉給你!你懂得。這是window下的,linux下直接給你報錯!沒事了就!所一系統通過jcb控制進程。JCB包含了進程號優先順序好多內容,你打開你的windows任務管理器看看進程是不是有好多屬性啊?那就是PCB(PRCESS,CONTROL BLOCK)同理作業也包含那些內容只是多少而已。下面寫出進程特點:
1、進程是分配計算機資源最小的單位。你想啊人是要用程序幹活的吧?你把程序調入內存成了就成了進程,所以說進程是分配資源的最小單位。你在linux下打開終端輸入top命令看是不是有好多進程?
2、進程有操作系統為作業產生。有「父進程」產生「子進程」之間是父子關系,並可以繼續向下產生「子進程」。還拿QQ來說,你雙擊QQ.exe。QQ啟動了輸入賬號密碼打開主界面了。這時候你要聊天,QQ進程趕緊產生個「兒子」說 「兒子你去陪主人聊天去吧。這樣子進程產生了。突然你想看美女要傳照片這時候那個」兒子「有」生「了一個」兒子「說」兒子「你去傳照片。那個「兒子領到任務去傳照片了。這時你想關了QQ,QQ提示你說」你還有個「兒子」和「孫子」還在幹活呢你真要結束嗎?你蒽了確定。QQ對他「兒子」(你聊天窗口)說:」兒子啊對不起了,主人要關閉我你也不能活啊「咔嚓一下」兒子「死了,兒子死之前對他兒子說:「兒子啊你爺爺不讓我活了,你也別活了咔嚓孫子也死了。最後世界安靜了。這就是進程的父子關系。能明白嗎?記住:進程之活動在內存中。不能使用CPU,只管分配資源。
再說線程:線程也產生在內存中並且在內存中存在相當長的時間,但它的活動區域主要在CPU中,並且運行和滅亡都存在於CPU中,可以這么說,線程是程序中能被系統調度進入CPU中最小程序單位,它能直接使用進程分配的CPU的資源。
還拿QQ來說當你要傳文件時QQ總要判斷一下文件的擴展名吧,ok這時那個」兒子「趕緊對它爸爸說我需要一個線程判斷擴展名QQ趕緊對一個管這個的線程說:」快點去CPU里計算下那個擴展名是什麼然後向主人報告計算完了就「死了」消亡了,但是它的線程還在內存中!還等著你下一次傳文件然後計算然後消亡!
線程之間是相互獨立的。一個在CPU,一個在內存里還能有關系嗎對不?CPU在每一個瞬間只能進入一個線程,當線程進入CPU時立即產生一個新的線程,新線程仍停留在內存中,就好比上面那個傳文件還會等著你再傳文件再計算擴展名。
線程相對線程是獨立的,但它在內存中並不是獨立的,這就好比你不開QQ能用QQ傳輸文件嗎?它只存在與進程分配的資源中,也就是說計算擴展名這個線程只能停留在QQ這個進程中,不能跑到別的進程里!!相當於程序產生了新的進程和線程,進程向CPU申請資源,再有線程來使用,他們都是為程序服務的只是分工不同!
因為你沒提問linux下是怎麼管理進程和線程的所以我就不回答了,這個問題我建議你還是看看《笨兔兔的故事》裡面講到了linux是怎麼管理進程和線程的。挺幽默的比我說得還好。
你第二個問題說實話我回答不了你!我想你現在連進程和線程還沒理解第二個你更理解不了了你說對不?我猜的其實你用C/C++不管是在windows下編程還是在Linux下編程思想都是一樣的對吧,如果你理解了在windows下線程間通信,在linux更沒問題了!
參考資料:黑客手冊2009合訂本非安全第一二季244頁,245頁,328頁,329頁,398頁,399頁
淺談操作系統原理 (一 二三)
ubuntu中文論壇 笨兔兔的故事
http://forum.ubuntu.org.cn/viewtopic.php?f=120&t=267518
希望我的回答你能理解

Ⅱ 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;
}

Ⅲ Linux 多線程編程(二)2019-08-10

三種專門用於線程同步的機制:POSIX信號量,互斥量和條件變數.

在Linux上信號量API有兩組,一組是System V IPC信號量,即PV操作,另外就是POSIX信號量,POSIX信號量的名字都是以sem_開頭.

phshared參數指定信號量的類型,若其值為0,就表示這個信號量是當前進程的局部信號量,否則該信號量可以在多個進程之間共享.value值指定信號量的初始值,一般與下面的sem_wait函數相對應.

其中比較重要的函數sem_wait函數會以原子操作的方式將信號量的值減一,如果信號量的值為零,則sem_wait將會阻塞,信號量的值可以在sem_init函數中的value初始化;sem_trywait函數是sem_wait的非阻塞版本;sem_post函數將以原子的操作對信號量加一,當信號量的值大於0時,其他正在調用sem_wait等待信號量的線程將被喚醒.
這些函數成功時返回0,失敗則返回-1並設置errno.

生產者消費者模型:
生產者對應一個信號量:sem_t procer;
消費者對應一個信號量:sem_t customer;
sem_init(&procer,2)----生產者擁有資源,可以工作;
sem_init(&customer,0)----消費者沒有資源,阻塞;

在訪問公共資源前對互斥量設置(加鎖),確保同一時間只有一個線程訪問數據,在訪問完成後再釋放(解鎖)互斥量.
互斥鎖的運行方式:串列訪問共享資源;
信號量的運行方式:並行訪問共享資源;
互斥量用pthread_mutex_t數據類型表示,在使用互斥量之前,必須使用pthread_mutex_init函數對它進行初始化,注意,使用完畢後需調用pthread_mutex_destroy.

pthread_mutex_init用於初始化互斥鎖,mutexattr用於指定互斥鎖的屬性,若為NULL,則表示默認屬性。除了用這個函數初始化互斥所外,還可以用如下方式初始化:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER。
pthread_mutex_destroy用於銷毀互斥鎖,以釋放佔用的內核資源,銷毀一個已經加鎖的互斥鎖將導致不可預期的後果。

pthread_mutex_lock以原子操作給一個互斥鎖加鎖。如果目標互斥鎖已經被加鎖,則pthread_mutex_lock則被阻塞,直到該互斥鎖佔有者把它給解鎖.
pthread_mutex_trylock和pthread_mutex_lock類似,不過它始終立即返回,而不論被操作的互斥鎖是否加鎖,是pthread_mutex_lock的非阻塞版本.當目標互斥鎖未被加鎖時,pthread_mutex_trylock進行加鎖操作;否則將返回EBUSY錯誤碼。注意:這里討論的pthread_mutex_lock和pthread_mutex_trylock是針對普通鎖而言的,對於其他類型的鎖,這兩個加鎖函數會有不同的行為.
pthread_mutex_unlock以原子操作方式給一個互斥鎖進行解鎖操作。如果此時有其他線程正在等待這個互斥鎖,則這些線程中的一個將獲得它.


三個列印機輪流列印:

輸出結果:

如果說互斥鎖是用於同步線程對共享數據的訪問的話,那麼條件變數就是用於在線程之間同步共享數據的值.條件變數提供了一種線程之間通信的機制:當某個共享數據達到某個值時,喚醒等待這個共享數據的線程.
條件變數會在條件不滿足的情況下阻塞線程.且條件變數和互斥量一起使用,允許線程以無競爭的方式等待特定的條件發生.

其中pthread_cond_broadcast函數以廣播的形式喚醒所有等待目標條件變數的線程,pthread_cond_signal函數用於喚醒一個等待目標條件變數線程.但有時候我們可能需要喚醒一個固定的線程,可以通過間接的方法實現:定義一個能夠唯一標識目標線程的全局變數,在喚醒等待條件變數的線程前先設置該變數為目標線程,然後採用廣播的方式喚醒所有等待的線程,這些線程被喚醒之後都檢查該變數以判斷是否是自己.

採用條件變數+互斥鎖實現生產者消費者模型:

運行結果:

阻塞隊列+生產者消費者

運行結果:

c語言實例,linux線程同步的信號量方式 謝謝

這么高的懸賞,實例放後面。信號量(sem),如同進程一樣,線程也可以通過信號量來實現通信,雖然是輕量級的。信號量函數的名字都以"sem_"打頭。線程使用的基本信號量函數有四個。

信號量初始化。
intsem_init(sem_t*sem,intpshared,unsignedintvalue);
這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux只支持為0,即表示它是當前進程的局部信號量),然後給它一個初始值VALUE。
等待信號量。給信號量減1,然後等待直到信號量的值大於0。
intsem_wait(sem_t*sem);
釋放信號量。信號量值加1。並通知其他等待線程。
intsem_post(sem_t*sem);
銷毀信號量。我們用完信號量後都它進行清理。歸還佔有的一切資源。
intsem_destroy(sem_t*sem);
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<errno.h>
#definereturn_if_fail(p)if((p)==0){printf("[%s]:funcerror!/n",__func__);return;}
typedefstruct_PrivInfo
{
sem_ts1;
sem_ts2;
time_tend_time;
}PrivInfo;
staticvoidinfo_init(PrivInfo*thiz);
staticvoidinfo_destroy(PrivInfo*thiz);
staticvoid*pthread_func_1(PrivInfo*thiz);
staticvoid*pthread_func_2(PrivInfo*thiz);
intmain(intargc,char**argv)
{
pthread_tpt_1=0;
pthread_tpt_2=0;
intret=0;
PrivInfo*thiz=NULL;
thiz=(PrivInfo*)malloc(sizeof(PrivInfo));
if(thiz==NULL)
{
printf("[%s]:Failedtomallocpriv./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);
return0;
}
staticvoidinfo_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;
}
staticvoidinfo_destroy(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
sem_destroy(&thiz->s1);
sem_destroy(&thiz->s2);
free(thiz);
thiz=NULL;
return;
}
staticvoid*pthread_func_1(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
while(time(NULL)<thiz->end_time)
{
sem_wait(&thiz->s2);
printf("pthread1:pthread1getthelock./n");
sem_post(&thiz->s1);
printf("pthread1:pthread1unlock/n");
sleep(1);
}
return;
}
staticvoid*pthread_func_2(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
while(time(NULL)<thiz->end_time)
{
sem_wait(&thiz->s1);
printf("pthread2:pthread2gettheunlock./n");
sem_post(&thiz->s2);
printf("pthread2:pthread2unlock./n");
sleep(1);
}
return;
}

Ⅳ linux下 進程信號量和線程信號量的區別和聯系是什麼

信號量在進程是以有名信號量進行通信的,在線程是以無名信號進行通信的,因為線程linux還沒有實現進程間的通信,所以在sem_init的第二個參數要為0,而且在多線程間的同步是可以通過有名信號量也可通過無名信號,但是一般情況線程的同步是無名信號量,無名信號量使用簡單,而且sem_t存儲在進程空間中,有名信號量必須LINUX內核管理,由內核結構struct ipc_ids 存儲,是隨內核持續的,系統關閉,信號量則刪除,當然也可以顯示刪除,通過系統調用刪除,
消息隊列,信號量,內存共享,這幾個都是一樣的原理。,只不過信號量分為有名與無名

Ⅵ Linux中,shell腳本如何使用信號機制去控制線程的開啟關閉

trap是Linux的內建命令,用於捕捉信號,trap命令可以指定收到某種信號時所執行的命令。trap命令的格式如下:trap command sig1 sig2 ... sigN,當接收到sinN中任意一個信號時,執行command命令,command命令完成後繼續接收到信號前的操作,直到腳本結束。利用trap命令捕捉INT信號(即與Ctrl+c綁定的中斷信號)。trap還可以忽略某些信號,將command用空字元串代替即可,如trap "" TERM INT,忽略kill %n和Ctrl+c發送的信號(kill發送的是TERM信號)。Linux更強勁的殺死進程的命令:kill -9 進程號(或kill -9 %n作業號)等價與kill -KILL 進程號。

舉個例子

最近小A需要生產2015年全年的KPI數據報表,現在小A已經將生產腳本寫好了,生產腳本一次只能生產指定一天的KPI數據,假設跑一次生產腳本需要5分鍾,那麼:

如果是循環順序執行,那麼需要時間:5 * 365 = 1825 分鍾,約等於 6 天

如果是一次性放到linux後台並發執行,365個後台任務,系統可承受不住哦!

既然不能一次性把365個任務放到linux後台執行,那麼,能不能實現自動地每次將N個任務放到後台並發執行呢?當然是可以的啦。

#!/bin/bash
source/etc/profile;
#-----------------------------
tempfifo=$$.fifo#$$表示當前執行文件的PID
begin_date=$1#開始時間
end_date=$2#結束時間
if[$#-eq2]
then
if["$begin_date">"$end_date"]
then
echo"Error!$begin_dateisgreaterthan$end_date"
exit1;
fi
else
echo"Error!Notenoughparams."
echo"Sample:shloop_kpi2015-12-012015-12-07"
exit2;
fi
#-----------------------------
trap"exec1000>&-;exec1000<&-;exit0"2
mkfifo$tempfifo
exec1000<>$tempfifo
rm-rf$tempfifo
for((i=1;i<=8;i++))
do
echo>&1000
done
while[$begin_date!=$end_date]
do
read-u1000
{
echo$begin_date
hive-fkpi_report.sql--hivevardate=$begin_date
echo>&1000
}&
begin_date=`date-d"+1day$begin_date"+"%Y-%m-%d"`
done
wait
echo"done!!!!!!!!!!"



第6~22行:比如:sh loop_kpi_report.sh 2015-01-01 2015-12-01:

$1表示腳本入參的第一個參數,等於2015-01-01

$2表示腳本入參的第二個參數,等於2015-12-01

$#表示腳本入參的個數,等於2

第13行用於比較傳入的兩個日期的大小,>是轉義

第26行:表示在腳本運行過程中,如果接收到Ctrl+C中斷命令,則關閉文件描述符1000的讀寫,並正常退出

exec 1000>&-;表示關閉文件描述符1000的寫

exec 1000<&-;表示關閉文件描述符1000的讀

trap是捕獲中斷命令

第27~29行:

第27行,創建一個管道文件

第28行,將文件描述符1000與FIFO進行綁定,<讀的綁定,>寫的綁定,<>則標識對文件描述符1000的所有操作等同於對管道文件$tempfifo的操作

第29行,可能會有這樣的疑問:為什麼不直接使用管道文件呢?事實上這並非多此一舉,管道的一個重要特性,就是讀寫必須同時存在,缺失某一個操作,另一個操作就是滯留,而第28行的綁定文件描述符(讀、寫綁定)正好解決了這個問題

第31~34行:對文件描述符1000進行寫入操作。通過循環寫入8個空行,這個8就是我們要定義的後台並發的線程數。為什麼是寫空行而不是寫其它字元?因為管道文件的讀取,是以行為單位的

第37~42行:

第37行,read -u1000的作用就是讀取管道中的一行,在這里就是讀取一個空行;每次讀取管道就會減少一個空行

第39~41行,注意到第42行結尾的&嗎?它表示進程放到linux後台中執行

第41行,執行完後台任務之後,往文件描述符1000中寫入一個空行。這是關鍵所在了,由於read -u1000每次操作,都會導致管道減少一個空行,當linux後台放入了8個任務之後,由於文件描述符1000沒有可讀取的空行,將導致read -u1000一直處於等待。

Ⅶ Linux 中有名信號量,異常關閉其他線程如何獲取

linux下進程間同步的機制有以下三種:
信號量
記錄鎖(文件鎖)
共享內存中的mutex
效率上 共享內存mutex > 信號量 > 記錄鎖
posix 提供了新的信號量 - 有名信號量,既可以使用在進程間同步也可以作為線程間同步的手段。效率比共享內存mutex要好一些

Ⅷ Linux線程及同步

linux多線程
1.線程概述
線程是一個進程內的基本調度單位,也可以稱為輕量級進程。線程是在共享內存空間中並發的多道執行路徑,它們共享一個進程的資源,如文件描述和信號處理。因此,大大減少了上下文切換的開銷。一個進程可以有多個線程,也就
是有多個線程式控制製表及堆棧寄存器,但卻共享一個用戶地址空間。
2.線程實現
線程創建pthread_create()
所需頭文件#include
<pthread.h>
函數原型int
pthread_create
((pthread_t
*thread,
pthread_attr_t
*attr,
thread:線程標識符
attr:線程屬性設置
start_routine:線程函數的起始地址
arg:傳遞給start_routine的參數
函數返回值
成功:0
出錯:-1
線程退出pthread_exit();
所需頭文件#include
<pthread.h>
函數原型void
pthread_exit(void
*retval)
函數傳入值retval:pthread_exit()調用者線程的返回值,可由其他函數如pthread_join
來檢索獲取
等待線程退出並釋放資源pthread_join()
所需頭文件#include
<pthread.h>
函數原型int
pthread_join
((pthread_t
th,
void
**thread_return))
函數傳入值
th:等待線程的標識符
thread_return:用戶定義的指針,用來存儲被等待線程的返回值(不為NULL時)
函數返回值
成功:0
出錯:-1
代碼舉例
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
/*線程1*/
6.
void
thread1()
7.
{
8.
int
i=0;
9.
10.
while(1)
11.
{
12.
printf(thread1:%d/n,i);
13.
if(i>3)
14.
pthread_exit(0);
15.
i++;
16.
sleep(1);
17.
}
18.
}
19.
20.
/*線程2*/
21.
void
thread2()
22.
{
23.
int
i=0;
24.
25.
while(1)
26.
{
27.
printf(thread2:%d/n,i);
28.
if(i>5)
29.
pthread_exit(0);
30.
i++;
31.
sleep(1);
32.
}
33.
}
34.
35.
int
main()
36.
{
37.
pthread_t
t1,t2;
38.
39.
/*創建線程*/
40.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
41.
pthread_create(&t2,NULL,(void
*)thread2,NULL);
42.
/*等待線程退出*/
43.
pthread_join(t1,NULL);
44.
pthread_join(t2,NULL);
45.
return
0;
46.
}
3同步與互斥
<1>互斥鎖
互斥鎖的操作主要包括以下幾個步驟。

互斥鎖初始化:pthread_mutex_init

互斥鎖上鎖:pthread_mutex_lock

互斥鎖判斷上鎖:pthread_mutex_trylock

互斥鎖接鎖:pthread_mutex_unlock

消除互斥鎖:pthread_mutex_destroy
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
int
i=0;/*共享變數*/
6.
pthread_mutex_t
mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥鎖*/
7.
8.
void
thread1()
9.
{
10.
int
ret;
11.
while(1)
12.
{
13.
14.
15.
ret=pthread_mutex_trylock(&mutex);/*判斷上鎖*/
16.
17.
if(ret!=EBUSY)
18.
{
19.
pthread_mutex_lock(&mutex);/*上鎖*/
20.
printf(This
is
thread1:%d/n,i);
21.
i++;
22.
pthread_mutex_unlock(&mutex);/*解鎖*/
23.
}
24.
sleep(1);
25.
}
26.
}
27.
28.
void
thread2()
29.
{int
ret;
30.
while(1)
31.
{
32.
33.
ret=pthread_mutex_trylock(&mutex);
34.
if(ret!=EBUSY)
35.
{
36.
pthread_mutex_lock(&mutex);
37.
printf(This
is
thread2:%d/n,i);
38.
i++;
39.
pthread_mutex_unlock(&mutex);
40.
}
41.
sleep(1);
42.
}
43.
}
44.
int
main()
45.
{
46.
pthread_t
t1,t2;
47.
pthread_mutex_init(&mutex,NULL);
48.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
49.
pthread_create(&t2,NULL,(void
*)thread2,NULL);
50.
51.
pthread_join(t1,NULL);
52.
pthread_join(t2,NULL);
53.
54.
pthread_mutex_destroy(&mutex);
55.
return
0;
56.
}
<2>信號量
未進行同步處理的兩個線程
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
int
i=0;
6.
void
thread1()
7.
{
8.
9.
while(1)
10.
{
11.
printf(This
is
thread1:%d/n,i);
12.
i++;
13.
sleep(1);
14.
}
15.
}
16.
17.
18.
void
thread2()
19.
{
20.
21.
while(1)
22.
{
23.
printf(This
is
thread2:%d/n,i);
24.
i++;
25.
sleep(1);
26.
}
27.
}
28.
29.
int
main()
30.
{
31.
pthread_t
t1,t2;
32.
33.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
34.
pthread_create(&t2,NULL,(void
*)thread2,NULL);

Ⅸ 有人能教下我有關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);
每個線程都成功的鎖住一個互斥量,接著試圖對以為另一線程鎖定的互斥量加鎖,就會一直等下去
要避免此類死鎖問題,最簡單的就是定義互斥量的層級關系

Ⅹ 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

熱點內容
ottoandroid 發布:2024-11-30 03:40:48 瀏覽:552
argvpython 發布:2024-11-30 03:40:45 瀏覽:284
ofo單車密碼怎麼開 發布:2024-11-30 03:38:18 瀏覽:134
手機安卓安全更新什麼意思 發布:2024-11-30 03:35:25 瀏覽:466
塵歌壺怎麼修改配置 發布:2024-11-30 03:31:42 瀏覽:619
我的世界聯機為什麼無法連接至伺服器 發布:2024-11-30 03:05:49 瀏覽:48
安卓手機鎖屏的圖片在哪裡找到 發布:2024-11-30 03:00:49 瀏覽:189
安卓手機紅點怎麼去除 發布:2024-11-30 02:52:04 瀏覽:597
安卓手機屏幕標識怎麼變大 發布:2024-11-30 02:47:07 瀏覽:975
牆加密區域 發布:2024-11-30 02:33:32 瀏覽:631