Heim  >  Artikel  >  Betrieb und Instandhaltung  >  Detaillierte Einführung in die Multithread-Programmierung in C-Sprache unter Linux

Detaillierte Einführung in die Multithread-Programmierung in C-Sprache unter Linux

黄舟
黄舟Original
2017-10-14 11:00:422109Durchsuche

In diesem Artikel wird hauptsächlich die Multithread-Programmierung in C-Sprache unter Linux vorgestellt. Freunde, die es benötigen, können darauf verweisen

Wenn wir Linux-Dienste schreiben, verwenden wir häufig die Linux-Multithreading-Technologie, um die Programmleistung zu verbessern

Einige Tipps zum Multithreading:

Eine Anwendung kann mehrere Threads starten.

Thread (Lightweight Process, LWP) ist die kleinste Einheit der Programmausführung.

Im Allgemeinen verfügt das einfachste Programm über mindestens einen Thread, bei dem es sich um das Programm selbst handelt, dh um die Hauptfunktion (ein Single-Thread-Prozess kann einfach als Prozess mit nur einem Thread betrachtet werden)

Ein Thread ist blockiert. Andere Threads sind davon nicht betroffen.

Multithread-Prozesse können die CPU-Ressourcen des Systems so weit wie möglich nutzen.

1 Erstellen Sie einen Thread

Beginnen wir zunächst mit einem einfachen Code, der einen Thread in einem Prozess erstellt, und gehen wir dann tiefer.


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 printf("func run...\n");
 return NULL;
}
int main()
{
 pthread_t t1;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 sleep(1);
 return EXIT_SUCCESS;
}
int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

In der Hauptfunktion rufen wir die obige Funktion auf, um einen Thread zu erstellen.

Funktionsparameter:

Der erste Parameter: pthread_t stellt die eindeutige Kennung des erstellten Threads dar. Nachdem wir ihn erstellt haben, müssen wir ihn ändern Der Zeiger wird übergeben.

Der zweite Parameter: pthread_attr_t, stellt einige Konfigurationen zum Erstellen dieses Threads dar, z. B. die Größe des Zuordnungsstapels usw. . Im Allgemeinen können wir NULL eingeben, was die Standardkonfiguration für die Thread-Erstellung darstellt.

Der dritte Parameter: stellt die Adresse einer Funktion dar. Beim Erstellen eines Threads wird diese Funktion aufgerufen *, die Parameter der Funktion. Auch void*, das allgemeine Format ist wie folgt: void * func(void * arg){}

Der vierte Parameter: stellt den Parameter dar, der durch den Aufruf der dritten Funktion

Funktionsrückgabe übergeben wird Wert:

Die Funktion gibt erfolgreich 0 zurück. Wenn sie nicht gleich 0 ist, bedeutet dies, dass der Funktionsaufruf fehlgeschlagen ist. Zu diesem Zeitpunkt kann strerror(errno) verwendet werden, um den spezifischen Fehler auszudrucken.

Hinweis: Jeder Thread hat eine Kopie von errno, und verschiedene Threads haben unterschiedliche errno

Endlich zusammengestellt von gcc


gcc 1createthread.c -c -o 1createthread.o
gcc 1createthread.o -o thr1 -lpthread

Beim Kompilieren müssen Sie -lpthread hinzufügen, um die dynamische Bibliothek libpthread.so zu verknüpfen. Andernfalls wird angezeigt, dass die Funktion nicht gefunden werden kann

Der Funktionsaufruf gibt das Ergebnis zurück

Frage: Warum wird die Schlaffunktion aufgerufen? Alle Threads werden beendet.

2 Threads hängen

Manchmal erstellen wir einen weiteren Thread in einem Thread und der Hauptthread muss warten, bis der erstellte Thread zurückkehrt Der Hauptthread wird erst beendet, nachdem der Rückgabewert des Threads erhalten wurde. Zu diesem Zeitpunkt müssen Sie eine Fadenaufhängung verwenden.

Die Funktion pthread_join wird verwendet, um den aktuellen Thread anzuhalten, bis der durch th angegebene Thread beendet wird.

int pthread_join(pthread_t th, void **thr_return);。

Ergebnis der Funktionsausführung

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 for(;i<5;i++)
 {
  printf("func run%d\n",i);
  sleep(1);
 }
 int * p = (int *)malloc(sizeof(int));
 *p=11;
 return p;
}
int main()
{
 pthread_t t1,t2;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 void *p=NULL;
 pthread_join(t1,&p);
 printf("线程退出:code=%d\n",*(int*)p);
 return EXIT_SUCCESS;
}

Unsere Hauptfunktion hat darauf gewartet, dass die Ausführung des erstellten Threads abgeschlossen ist. und erhält den Rückgabewert des Endes der Thread-Ausführung

3 Thread-Beendigung

Exit()-Funktion, wenn der Prozess beendet wird, also was ist Thread-Beendigung? Drei Situationen der Thread-Beendigung:

Der Thread kehrt einfach von der Startfunktion zurück und der Rückgabewert ist der Exit-Code des Threads.

Threads können von anderen Threads im selben Prozess abgebrochen werden.

Der Thread ruft pthread_exit auf.

Die Parameter der pthread_exit-Funktion sind die gleichen wie bei der Rückgabe des normalen Thread-Endes und werden vom Haupt-Thread abgerufen, der auf sein Ende wartet.

Ergebnis der Funktionsausführung:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 while(1)
 {
  if(i==10)
  {
   int * p = (int *)malloc(sizeof(int));
   *p=11;
   pthread_exit(p);
  }
  printf("fun run %d\n",i++);
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 void *p=NULL;
 pthread_join(t1,&p);
 printf("线程退出:code=%d",*(int*)p);
 return EXIT_SUCCESS;
}
void pthread_exit(void *arg);

4-Thread-Trennung

Die Funktion pthread_detach versetzt den Thread in einen getrennten Zustand.

Wenn Sie nicht auf einen Thread warten und nicht am Rückgabewert des Threads interessiert sind, können Sie den Thread in den getrennten Zustand versetzen und das System die von ihm belegten Ressourcen automatisch recyceln lassen, wenn der Thread beendet wird.
int pthread_detach(pthread_t th);

Ein Thread kann pthread_detach nicht selbst aufrufen, um sich in den getrennten Zustand zu versetzen. Er kann pthread_detach nur von anderen Threads aufrufen.

5 Thread-Abbruch

Die pthread_cancel-Funktion ermöglicht es einem Thread, einen anderen Thread abzubrechen, der durch angegeben wird Thread.

Die Funktion gibt bei Erfolg 0 zurück, andernfalls gibt sie ungleich 0 zurück.
int pthread_cancel(pthread_t th);

Ergebnis der Funktionsausführung:

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func1(void * arg)
{
 while(1)
 {
  printf("fun run...\n");
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1;
 if(pthread_create(&t1,NULL,func1,NULL)!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
  return -1;
 }
 sleep(5);
 pthread_cancel(t1);
 pthread_join(t1,NULL);
 return EXIT_SUCCESS;
}

上面我们说过创建一个线程函数pthread_create的第二个参数,用来决定创建线程的一些初始化状态,这里我们 举个例子,改线程一创建就是分离状态的线程(

上面介绍了pthread_detach函数的概念,可以通过pthread_attr_t在创建线程的时候就指定线程属性为detach,而不用创建以后再去修改线程属性。

先上一段代码:


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 for(;i<5;i++)
 {
  printf("func run%d\n",i);
  sleep(1);
 }
 int * p = (int *)malloc(sizeof(int));
 *p=11;
 return p;
}
int main()
{
 pthread_t t1;
 pthread_attr_t attr;//申明一个attr的结构体
 pthread_attr_init(&attr);//初始化结构体
 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程为分离线程
 int err = pthread_create(&t1,&attr,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 pthread_attr_destroy(&attr);
 pthread_join(t1,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}

pthread_attr_t就是我们要传入的参数的结构体,一般申明的步骤有

1,申明一个pthread_attr_t对象

2,函数pthread_attr_init初始化attr结构。

3,设置线程的一些属性,比如pthread_attr_setdetachstate函数就是设置该线程创建的时候为正常状态还是分离状态。

4,函数pthread_attr_destroy释放attr内存空间

pthread_attr_setdetachstate把线程属性设置为下面两个合法值之一:

说明

PTHREAD_CREATE_DETACHED

设置线程为分离状态

PTHREAD_CREATE_JOINABLE

设置线程为正常状态

上面函数运行结果:

因为线程是个分离状态的,所以pthread_join挂起会失效,主线程很快运行结束,程序也就结束了,创建的线程还没来得及运行

线程同步

有时候我们多个线程处理订单扣减库存会遇到这样的问题,两个线程同时进入一段代码先查询库存,两个都查出来为还剩一件库存,第一个线程用掉这个库存后,将库存变为0,但是第二个线程刚才也查出来为1了,所以他还认为有库存,

这个时候操作就会引发我们想不到的意外,库存变为负数了!!所以这个时候就需要使用线程的同步!!

先上一段代码看看效果:


#include<pthread.h>
#include<stdio.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int threadno =*(int*)arg;
 int i=0;
 for(;i<10;i++)
 {
  printf("%d thread%d \n",threadno,i);
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int i1=1,i2=2;
 pthread_create(&t1,NULL,func,&i1);
 pthread_create(&t2,NULL,func,&i2);
 pthread_join(t1,NULL);
 pthread_join(t2,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}

函数运行结果:

可以看到两个线程是没有规律的争相处理的,如果这段代码是扣减库存就完蛋啦!,所以我们要对这段代码进行加锁,同一时刻只能有一个线程进入操作!

先上代码:


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * func(void * arg)
{
 pthread_mutex_lock(&mutex);//对mutex加锁,其他线程进入后将会挂起,知道这个锁被解锁
 int threadno =*(int*)arg;
 int i=0;
 for(;i<10;i++)
 {
  printf("%d thread%d \n",threadno,i);
  sleep(1);
 }
 pthread_mutex_unlock(&mutex);
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int i1=1,i2=2;
 pthread_create(&t1,NULL,func,&i1);
 pthread_create(&t2,NULL,func,&i2);
 pthread_join(t1,NULL);
 pthread_join(t2,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}

函数运行结果:

可以看到第二个线程先进入后一直运行结束,对mutex解锁后,第一个线程才能进方法里面运行!否则会挂起,一直等到锁被解锁!

PTHREAD_MUTEX_INITIALIZER是初始化一个快速锁的宏定义。


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

加锁解锁函数:


int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

总结

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in die Multithread-Programmierung in C-Sprache unter Linux. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn