線程

進程就是運行的程序,是爲了在CPU上實現多道編程而有的概念。但是進程在同一時刻只能幹一件事,如果想同時幹多件事,就要用到線程。線程可以運行在不同的處理器上,從未提高進程的執行效率。


在前面講進程我們知道,進程是一組有序指令、資源、數據的集合,今天要講的線程就是進程內部的一條執行序列(執行流)。每個進程至少有一條執行序列,main函數的執行體。進程可以通過線程創建n條線程,這些新創建的線程稱爲函數線程。main函數所代表的線程爲主線程。


那麼,進程和線程有什麼區別呢?

1、進程是資源分配的最小單位,線程是CPU調度的最小單位(CPU執行的實際上是線程中的指令)。

2、線程是輕量級的進程。

3、管理方式不同:進程是PCB管理,線程由線程結構管理。


線程實現的三種方式:

1、用戶態線程


優點:靈活,在任何操作系統上都可以用;線程切換快;不用修改系統操作,容易實現。

缺點:編程變得複雜,要知道什麼時候讓CPU給別的線程使用;用戶態線程無法完全達到線程提出所要達到的目的:進程級多道編程。


2、內核態線程


優點:用戶操作簡單。

缺點:效率較低;佔用內核態稀缺的資源。


3、混合態線程


用戶態的執行系統負責進程內部線程在非阻塞時切換;內核態的操作系統負責阻塞線程的切換,即我們同時實現內核態和用戶態的線程管理。


線程的創建(線程庫文件的使用):

int pthread_creat(pthread_t *id, pthread_attr_t *attr, void *(*fun)(void*), void *arg);

id 創建出來的線程ID,由於創建之前並不知道,所以先定義pthread_t id,然後傳id地址;

attr 屬性,NULL爲創建默認屬性的線程;

void *(*fun)(void*) 參數類型爲void*的一個函數指針;

arg 就是fun函數的參數。

成功返回0,出錯返回錯誤編碼。

該函數創建的是函數線程。函數線程不同於函數調用,函數調用是這一條執行流中的一部分;函數線程是創建出一條獨立的執行序列,他與主線程同時執行。

包含線程創建的源代碼想要生成可執行文件,必須執行gcc pthread pthread.c -lpthread命令。


線程結束:int pthread_exit(void*);

ptr 可以設置一些退出信息(線程的退出狀態)。進程中的其他線程可以通過pthread_join函數訪問到ptr。


等待線程結束:int pthread_join(pthread_t id, void**);


調用該函數的線程將一直阻塞,等待線程結束,並且可以獲得到等待的線程通過ptr設置的退出信息。void**爲ptr的地址。

取消一個線程:int pthread_cancel(pthread_t thread);

A線程要求B線程終止,通過B線程ID thread,可以請求取消B線程。在接受到取消請求的B線程可以通過函數pthread_setcancelstate設置自己的取消狀態。

int pthread_setcancelstate(int state,int *oldstate);

state:可以是PTHREAD_CANCEL_ENABLE允許線程接收取消請求;或者是PTHREAD_CANCEL_DISABLE忽略取消請求;

oldstate:用於獲取先前的取消狀態。不需要知道時傳NULL就可以。

如果取消請求被接受了,線程可以進入第二個控制層次,用pthread_setcanceltype設置取消類型。

int pthread_setcanceltype(int type,int *oldtype);

type:可以是PTHREAD_CANCEL_ASYNCHRONOUS在接收到取消請求後立刻採取行動,也可以是PTHREAD_CANCEL_DEFERRED在接收到取消請求後,一直等待,直到線程執行了下述函數之一後才採取行動。

pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。

oldtype:可以保存先前的狀態,如果不想知道先前的狀態傳NULL。


默認情況下,線程在啓動時的取消狀態爲PTHREAD_CANCEL_ENABLE,取消類型爲PTHREAD_CANCEL_DEFERRED。




線程函數傳參:
1、將值強轉成void*         int a = (int)arg;
該值的類型僅限於char、short、int、long類型。


2、將地址強轉成void*     int a = *(int*)arg;

這種方式任何類型都可以,但是如果運行一段時間纔是用參數的值,在這段時間內可能被更改。爲解決該問題,可以在調用pthread_create函數後,先sleep(2),把值傳遞過去後主線程再運行。


 #include<stdio.h>
 #include<string.h>
 #include<assert.h>
 #include<unistd.h>
 #include<pthread.h>
  
 int Ispirmer(int n)//判斷是否是素數
 {
     int i = 2;
     for(;i<n/2;i++)
     {
          if(n%i == 0)
         {
             return 0;
          }
      }
      return 1;
  }
  
  BubbleSort(int *arr,int len)//冒泡排序
  {
      int i;
      int j;
      for(i=0;i<len-1;i++)
      {
          for(j=0;j<len-1-i;j++)
          {
              if(arr[j] > arr[j+1])
              {
                  int tmp;
                  tmp = arr[j];
                  arr[j] = arr[j+1];
                  arr[j+1] = tmp;
              }
          }
      }
  }
  void *pthread_fun(void *arg)//函數線程
  {
      int i = 2;
      for(;i<100;i++)
      {
          if(Ispirmer(i))
         {
             printf("%d ",i);
          }
      }
  
      printf("\n");
  
      pthread_exit("hello");
  }
  
  int main()
  {
      pthread_t id;
      int ret = pthread_create(&id,NULL,pthread_fun,NULL);
      assert(ret == 0);
  
      int arr[] = {2,4,1,7,3,8,4,9,23};
      int len = sizeof(arr)/sizeof(arr[0]);
  
      BubbleSort(arr,len);
  
      int i = 0;
      for(;i<len;i++)
      {
          printf("%d ",arr[i]);
     }
      printf("\n");
  
      char *p = NULL;
      pthread_join(id,&p);
  
  }






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章