国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

多線程編程之:Linux線程編程

發(fā)布時(shí)間:2015-11-12 11:13    發(fā)布者:designapp
關(guān)鍵詞: Linux , 多線程 , 互斥
  9.2 Linux線程編程
  9.2.1 線程基本編程
  這里要講的線程相關(guān)操作都是用戶空間中的線程的操作。在Linux中,一般pthread線程庫(kù)是一套通用的線程庫(kù),是由POSIX提出的,因此具有很好的可移植性。
  (1)函數(shù)說明。
  創(chuàng)建線程實(shí)際上就是確定調(diào)用該線程函數(shù)的入口點(diǎn),這里通常使用的函數(shù)是pthread_create()。在線程創(chuàng)建以后,就開始運(yùn)行相關(guān)的線程函數(shù),在該函數(shù)運(yùn)行完之后,該線程也就退出了,這也是線程退出一種方法。另一種退出線程的方法是使用函數(shù)pthread_exit(),這是線程的主動(dòng)行為。這里要注意的是,在使用線程函數(shù)時(shí),不能隨意使用exit()退出函數(shù)進(jìn)行出錯(cuò)處理,由于exit()的作用是使調(diào)用進(jìn)程終止,往往一個(gè)進(jìn)程包含多個(gè)線程,因此,在使用exit()之后,該進(jìn)程中的所有線程都終止了。因此,在線程中就可以使用pthread_exit()來代替進(jìn)程中的exit()。
  由于一個(gè)進(jìn)程中的多個(gè)線程是共享數(shù)據(jù)段的,因此通常在線程退出之后,退出線程所占用的資源并不會(huì)隨著線程的終止而得到釋放。正如進(jìn)程之間可以用wait()系統(tǒng)調(diào)用來同步終止并釋放資源一樣,線程之間也有類似機(jī)制,那就是pthread_join()函數(shù)。pthread_join()可以用于將當(dāng)前線程掛起來等待線程的結(jié)束。這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí),被等待線程的資源就被收回。
  前面已提到線程調(diào)用pthread_exit()函數(shù)主動(dòng)終止自身線程。但是在很多線程應(yīng)用中,經(jīng)常會(huì)遇到在別的線程中要終止另一個(gè)線程的執(zhí)行的問題。此時(shí)調(diào)用pthread_cancel()函數(shù)實(shí)現(xiàn)這種功能,但在被取消的線程的內(nèi)部需要調(diào)用pthread_setcancel()函數(shù)和pthread_setcanceltype()函數(shù)設(shè)置自己的取消狀態(tài),例如被取消的線程接收到另一個(gè)線程的取消請(qǐng)求之后,是接受還是忽略這個(gè)請(qǐng)求;如果接受,是立刻進(jìn)行終止操作還是等待某個(gè)函數(shù)的調(diào)用等。
  (2)函數(shù)格式。
  表9.1列出了pthread_create()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.2列出了pthread_exit()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.3列出了pthread_join()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.4列出了pthread_cancel()函數(shù)的語(yǔ)法要點(diǎn)。

  (3)函數(shù)使用。
  以下實(shí)例中創(chuàng)建了3個(gè)線程,為了更好地描述線程之間的并行執(zhí)行,讓3個(gè)線程重用同一個(gè)執(zhí)行函數(shù)。每個(gè)線程都有5次循環(huán)(可以看成5個(gè)小任務(wù)),每次循環(huán)之間會(huì)隨機(jī)等待1~10s的時(shí)間,意義在于模擬每個(gè)任務(wù)的到達(dá)時(shí)間是隨機(jī)的,并沒有任何特定規(guī)律。
  /* thread.c */
  #include
  #include
  #include
  #define THREAD_NUMBER 3 /*線程數(shù)*/
  #define REPEAT_NUMBER 5 /*每個(gè)線程中的小任務(wù)數(shù)*/
  #define DELAY_TIME_LEVELS 10.0 /*小任務(wù)之間的最大時(shí)間間隔*/
  void *thrd_func(void *arg)
  { /* 線程函數(shù)例程 */
  int thrd_num = (int)arg;
  int delay_time = 0;
  int count = 0;
  printf("Thread %d is starting\n", thrd_num);
  for (count = 0; count 多線程 */
  res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
  if (res != 0)
  {
  printf("Create thread %d failed\n", no);
  exit(res);
  }
  }
  printf("Create treads success\n Waiting for threads to finish...\n");
  for (no = 0; no 互斥
  由于線程共享進(jìn)程的資源和地址空間,因此在對(duì)這些資源進(jìn)行操作時(shí),必須考慮到線程間資源訪問的同步與互斥問題。這里主要介紹POSIX中兩種線程同步機(jī)制,分別為互斥鎖和信號(hào)量。這兩個(gè)同步機(jī)制可以互相通過調(diào)用對(duì)方來實(shí)現(xiàn),但互斥鎖更適合用于同時(shí)可用的資源是惟一的情況;信號(hào)量更適合用于同時(shí)可用的資源為多個(gè)的情況。
  1.互斥鎖線程控制
  (1)函數(shù)說明。
  互斥鎖是用一種簡(jiǎn)單的加鎖方法來控制對(duì)共享資源的原子操作。這個(gè)互斥鎖只有兩種狀態(tài),也就是上鎖和解鎖,可以把互斥鎖看作某種意義上的全局變量。在同一時(shí)刻只能有一個(gè)線程掌握某個(gè)互斥鎖,擁有上鎖狀態(tài)的線程能夠?qū)蚕碣Y源進(jìn)行操作。若其他線程希望上鎖一個(gè)已經(jīng)被上鎖的互斥鎖,則該線程就會(huì)掛起,直到上鎖的線程釋放掉互斥鎖為止。可以說,這把互斥鎖保證讓每個(gè)線程對(duì)共享資源按順序進(jìn)行原子操作。
  互斥鎖機(jī)制主要包括下面的基本函數(shù)。
  n 互斥鎖初始化:pthread_mutex_init()
  n 互斥鎖上鎖:pthread_mutex_lock()
  n 互斥鎖判斷上鎖:pthread_mutex_trylock()
  n 互斥鎖接鎖:pthread_mutex_unlock()
  n 消除互斥鎖:pthread_mutex_destroy()
  其中,互斥鎖可以分為快速互斥鎖、遞歸互斥鎖和檢錯(cuò)互斥鎖。這3種鎖的區(qū)別主要在于其他未占有互斥鎖的線程在希望得到互斥鎖時(shí)是否需要阻塞等待。快速鎖是指調(diào)用線程會(huì)阻塞直至擁有互斥鎖的線程解鎖為止。遞歸互斥鎖能夠成功地返回,并且增加調(diào)用線程在互斥上加鎖的次數(shù),而檢錯(cuò)互斥鎖則為快速互斥鎖的非阻塞版本,它會(huì)立即返回并返回一個(gè)錯(cuò)誤信息。默認(rèn)屬性為快速互斥鎖。
  (2)函數(shù)格式。
  表9.5列出了pthread_mutex_init()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.6列出了pthread_mutex_lock()等函數(shù)的語(yǔ)法要點(diǎn)。

  (3)使用實(shí)例。
  下面的實(shí)例是在9.2.1小節(jié)示例代碼的基礎(chǔ)上增加互斥鎖功能,實(shí)現(xiàn)原本獨(dú)立與無序的多個(gè)線程能夠按順序執(zhí)行。
  /*thread_mutex.c*/
  #include
  #include
  #include
  #define THREAD_NUMBER 3 /* 線程數(shù) */
  #define REPEAT_NUMBER 3 /* 每個(gè)線程的小任務(wù)數(shù) */
  #define DELAY_TIME_LEVELS 10.0 /*小任務(wù)之間的最大時(shí)間間隔*/
  pthread_mutex_t mutex;
  void *thrd_func(void *arg)
  {
  int thrd_num = (int)arg;
  int delay_time = 0, count = 0;
  int res;
  /* 互斥鎖上鎖 */
  res = pthread_mutex_lock(&mutex);
  if (res)
  {
  printf("Thread %d lock failed\n", thrd_num);
  pthread_exit(NULL);
  }
  printf("Thread %d is starting\n", thrd_num);
  for (count = 0; count 互斥。信號(hào)量本質(zhì)上是一個(gè)非負(fù)的整數(shù)計(jì)數(shù)器,它被用來控制對(duì)公共資源的訪問。這里先來簡(jiǎn)單復(fù)習(xí)一下PV原子操作的工作原理。
  PV原子操作是對(duì)整數(shù)計(jì)數(shù)器信號(hào)量sem的操作。一次P操作使sem減一,而一次V操作使sem加一。進(jìn)程(或線程)根據(jù)信號(hào)量的值來判斷是否對(duì)公共資源具有訪問權(quán)限。當(dāng)信號(hào)量sem的值大于等于零時(shí),該進(jìn)程(或線程)具有公共資源的訪問權(quán)限;相反,當(dāng)信號(hào)量sem的值小于零時(shí),該進(jìn)程(或線程)就將阻塞直到信號(hào)量sem的值大于等于0為止。
  PV原子操作主要用于進(jìn)程或線程間的同步和互斥這兩種典型情況。若用于互斥,幾個(gè)進(jìn)程(或線程)往往只設(shè)置一個(gè)信號(hào)量sem,它們的操作流程如圖9.2所示。
  當(dāng)信號(hào)量用于同步操作時(shí),往往會(huì)設(shè)置多個(gè)信號(hào)量,并安排不同的初始值來實(shí)現(xiàn)它們之間的順序執(zhí)行,它們的操作流程如圖9.3所示。
  


  


  圖9.2 信號(hào)量互斥操作 圖9.3 信號(hào)量同步操作
  (2)函數(shù)說明。
  Linux實(shí)現(xiàn)了POSIX的無名信號(hào)量,主要用于線程間的互斥與同步。這里主要介紹幾個(gè)常見函數(shù)。
  n sem_init()用于創(chuàng)建一個(gè)信號(hào)量,并初始化它的值。
  n sem_wait()和sem_trywait()都相當(dāng)于P操作,在信號(hào)量大于零時(shí)它們都能將信號(hào)量的值減一,兩者的區(qū)別在于若信號(hào)量小于零時(shí),sem_wait()將會(huì)阻塞進(jìn)程,而sem_trywait()則會(huì)立即返回。
  n sem_post()相當(dāng)于V操作,它將信號(hào)量的值加一同時(shí)發(fā)出信號(hào)來喚醒等待的進(jìn)程。
  n sem_getvalue()用于得到信號(hào)量的值。
  n sem_destroy()用于刪除信號(hào)量。
  (3)函數(shù)格式。
  表9.7列出了sem_init()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.8列出了sem_wait()等函數(shù)的語(yǔ)法要點(diǎn)。

  (4)使用實(shí)例。
  在前面已經(jīng)通過互斥鎖同步機(jī)制實(shí)現(xiàn)了多線程的順序執(zhí)行。下面的例子是用信號(hào)量同步機(jī)制實(shí)現(xiàn)3個(gè)線程之間的有序執(zhí)行,只是執(zhí)行順序是跟創(chuàng)建線程的順序相反。
  /*thread_sem.c*/
  #include
  #include
  #include
  #include
  #define THREAD_NUMBER 3 /* 線程數(shù) */
  #define REPEAT_NUMBER 3 /* 每個(gè)線程中的小任務(wù)數(shù) */
  #define DELAY_TIME_LEVELS 10.0 /*小任務(wù)之間的最大時(shí)間間隔*/
  sem_t sem[THREAD_NUMBER];
  void *thrd_func(void *arg)
  {
  int thrd_num = (int)arg;
  int delay_time = 0;
  int count = 0;
  /* 進(jìn)行P操作 */
  sem_wait(&sem[thrd_num]);
  printf("Thread %d is starting\n", thrd_num);
  for (count = 0; count = 0; no--)
  {
  res = pthread_join(thread[no], &thrd_ret);
  if (!res)
  {
  printf("Thread %d joined\n", no);
  }
  else
  {
  printf("Thread %d join failed\n", no);
  }
  /* 進(jìn)行V操作 */
  sem_post(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]);
  }
  for (no = 0; no Linux中采用“一對(duì)一”的線程機(jī)制,也就是一個(gè)用戶線程對(duì)應(yīng)一個(gè)內(nèi)核線程。綁定屬性就是指一個(gè)用戶線程固定地分配給一個(gè)內(nèi)核線程,因?yàn)镃PU時(shí)間片的調(diào)度是面向內(nèi)核線程(也就是輕量級(jí)進(jìn)程)的,因此具有綁定屬性的線程可以保證在需要的時(shí)候總有一個(gè)內(nèi)核線程與之對(duì)應(yīng)。而與之對(duì)應(yīng)的非綁定屬性就是指用戶線程和內(nèi)核線程的關(guān)系不是始終固定的,而是由系統(tǒng)來控制分配的。
  n 分離屬性。
  分離屬性是用來決定一個(gè)線程以什么樣的方式來終止自己。在非分離情況下,當(dāng)一個(gè)線程結(jié)束時(shí),它所占用的系統(tǒng)資源并沒有被釋放,也就是沒有真正的終止。只有當(dāng)pthread_join()函數(shù)返回時(shí),創(chuàng)建的線程才能釋放自己占用的系統(tǒng)資源。而在分離屬性情況下,一個(gè)線程結(jié)束時(shí)立即釋放它所占有的系統(tǒng)資源。這里要注意的一點(diǎn)是,如果設(shè)置一個(gè)線程的分離屬性,而這個(gè)線程運(yùn)行又非常快,那么它很可能在pthread_create()函數(shù)返回之前就終止了,它終止以后就可能將線程號(hào)和系統(tǒng)資源移交給其他的線程使用,這時(shí)調(diào)用pthread_create()的線程就得到了錯(cuò)誤的線程號(hào)。
  這些屬性的設(shè)置都是通過特定的函數(shù)來完成的,通常首先調(diào)用pthread_attr_init()函數(shù)進(jìn)行初始化,之后再調(diào)用相應(yīng)的屬性設(shè)置函數(shù),最后調(diào)用pthread_attr_destroy()函數(shù)對(duì)分配的屬性結(jié)構(gòu)指針進(jìn)行清理和回收。設(shè)置綁定屬性的函數(shù)為pthread_attr_setscope(),設(shè)置線程分離屬性的函數(shù)為pthread_attr_setdetachstate(),設(shè)置線程優(yōu)先級(jí)的相關(guān)函數(shù)為pthread_attr_getschedparam()(獲取線程優(yōu)先級(jí))和pthread_attr_setschedparam()(設(shè)置線程優(yōu)先級(jí))。在設(shè)置完這些屬性后,就可以調(diào)用pthread_create()函數(shù)來創(chuàng)建線程了。
  (2)函數(shù)格式。
  表9.9列出了pthread_attr_init()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.10列出了pthread_attr_setscope()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.11列出了pthread_attr_setdetachstate()函數(shù)的語(yǔ)法要點(diǎn)。

  表9.12 pthread_attr_getschedparam()函數(shù)語(yǔ)法要點(diǎn)

  表9.13列出了pthread_attr_setschedparam()函數(shù)的語(yǔ)法要點(diǎn)。

  (3)使用實(shí)例。
  下面的實(shí)例是在我們已經(jīng)很熟悉的實(shí)例的基礎(chǔ)上增加線程屬性設(shè)置的功能。為了避免不必要的復(fù)雜性,這里就創(chuàng)建一個(gè)線程,這個(gè)線程具有綁定和分離屬性,而且主線程通過一個(gè)finish_flag標(biāo)志變量來獲得線程結(jié)束的消息,而并不調(diào)用pthread_join()函數(shù)。
  /*thread_attr.c*/
  #include
  #include
  #include
  #define REPEAT_NUMBER 3 /* 線程中的小任務(wù)數(shù) */
  #define DELAY_TIME_LEVELS 10.0 /* 小任務(wù)之間的最大時(shí)間間隔 */
  int finish_flag = 0;
  void *thrd_func(void *arg)
  {
  int delay_time = 0;
  int count = 0;
  printf("Thread is starting\n");
  for (count = 0; count < REPEAT_NUMBER; count++)
  {
  delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
  sleep(delay_time);
  printf("\tThread : job %d delay = %d\n", count, delay_time);
  }
  printf("Thread finished\n");
  finish_flag = 1;
  pthread_exit(NULL);
  }
  int main(void)
  {
  pthread_t thread;
  pthread_attr_t attr;
  int no = 0, res;
  void * thrd_ret;
  srand(time(NULL));
  /* 初始化線程屬性對(duì)象 */
  res = pthread_attr_init(&attr);
  if (res != 0)
  {
  printf("Create attribute failed\n");
  exit(res);
  }
  /* 設(shè)置線程綁定屬性 */
  res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  /* 設(shè)置線程分離屬性 */
  res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  if (res != 0)
  {
  printf("Setting attribute failed\n");
  exit(res);
  }
  res = pthread_create(&thread, &attr, thrd_func, NULL);
  if (res != 0)
  {
  printf("Create thread failed\n");
  exit(res);
  }
  /* 釋放線程屬性對(duì)象 */
  pthread_attr_destroy(&attr);
  printf("Create tread success\n");
  while(!finish_flag)
  {
  printf("Waiting for thread to finish...\n");
  sleep(2);
  }
  return 0;
  }
  接下來可以在線程運(yùn)行前后使用“free”命令查看內(nèi)存的使用情況。以下是運(yùn)行結(jié)果:
  $ ./thread_attr
  Create tread success
  Waiting for thread to finish...
  Thread is starting
  Waiting for thread to finish...
  Thread : job 0 delay = 3
  Waiting for thread to finish...
  Thread : job 1 delay = 2
  Waiting for thread to finish...
  Waiting for thread to finish...
  Waiting for thread to finish...
  Waiting for thread to finish...
  Thread : job 2 delay = 9
  Thread finished
  /* 程序運(yùn)行之前 */
  $ free
  total used free shared buffers cached
  Mem: 255556 191940 63616 10 5864 61360
  -/+ buffers/cache: 124716 130840
  Swap: 377488 18352 359136
  /* 程序運(yùn)行之中 */
  $ free
  total used free shared buffers cached
  Mem: 255556 191948 63608 10 5888 61336
  -/+ buffers/cache: 124724 130832
  Swap: 377488 18352 359136
  /* 程序運(yùn)行之后 */
  $ free
  total used free shared buffers cached
  Mem: 255556 191940 63616 10 5904 61320
  -/+ buffers/cache: 124716 130840
  Swap: 377488 18352 359136
  可以看到,線程在運(yùn)行結(jié)束后就收回了系統(tǒng)資源,并釋放內(nèi)存。
                               
               
本文地址:http://www.qingdxww.cn/thread-156227-1-1.html     【打印本頁(yè)】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

廠商推薦

  • Microchip視頻專區(qū)
  • 無線充電基礎(chǔ)知識(shí)及應(yīng)用培訓(xùn)教程3
  • 了解一下Microchip強(qiáng)大的PIC18-Q24 MCU系列
  • PIC18-Q71系列MCU概述
  • 無線充電基礎(chǔ)知識(shí)及應(yīng)用培訓(xùn)教程2
  • 貿(mào)澤電子(Mouser)專區(qū)

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲欧美在线视频 | 日本欧美一区二区 | 国产麻豆精品免费密入口 | 国产精品久久久久9999小说 | 亚州中文 | 亚洲成a人片77777老司机 | 趁女同学洗澡摸她胸喝她奶 | 日本不卡免费高清一级视频 | 99热国内精品 | 日韩a在线看免费观看视频 日韩a在线观看 | 久久久国产精品va麻豆 | 国产精品香蕉在线观看不卡 | 欧美日本一区二区 | 老外一级毛片免费看 | 99九九成人免费视频精品 | 免费国产在线观看 | 日韩在线第一区 | 久久91精品国产一区二区 | 精品国产区 | 日本天堂视频在线观看 | 日本免费人成黄页网观看视频 | 免费一级毛片无毒不卡 | 全国最大色 | 国产一区二区三区视频在线观看 | 免费国产高清精品一区在线 | 国产在线精品成人一区二区三区 | 国产91精品高跟丝袜在线 | 啦啦啦中文在线影院观看 | 成年美女黄网站色大片免费看 | 欧美一区二区三区综合色视频 | www.色在线| 亚洲国产麻豆 | 国产在线精品99一卡2卡 | 开心激情五月婷婷 | 手机看片日韩高清国产欧美 | 中国bdsm国语对白视频 | 日产精品卡2卡三卡乱码网站 | sihu影院永久在线影院 | 欧洲1区二区三区二页 | 成年女人18毛片毛片免费 | 韩日一区二区 |