什么是多線程編程?
1、線程和進程的區(qū)別
進程是指正在運行的程序,它擁有獨立的內(nèi)存空間和系統(tǒng)資源,不同進程之間的數(shù)據(jù)不共享。
線程是進程內(nèi)的執(zhí)行單元,它與同一進程內(nèi)的其他線程共享進程的內(nèi)存空間和系統(tǒng)資源。
2、多線程的優(yōu)勢和應(yīng)用場景
多線程是一種并發(fā)編程方式,它的優(yōu)勢包括:
- 提高程序的響應(yīng)速度和運行效率(多核CPU下的多線程)
- 充分利用CPU資源,提高系統(tǒng)的利用率
- 支持多個任務(wù)并行執(zhí)行,提高程序的可擴展性和可維護性
Linux下的多線程編程
Linux下C語言多線程編程依賴于pthread多線程庫。pthread庫是Linux的多線程庫,是POSIX標準線程API的實現(xiàn),它提供了一種創(chuàng)建和操縱線程的方法,以及一些同步機制,如互斥鎖、條件變量等。
頭文件:
`#include < pthread.h >
`
編譯鏈接需要鏈接鏈接庫 pthread。
一、線程的基本操作
1、pthread_create
/**
* @brief 創(chuàng)建一個線程
*
* Detailed function description
*
* @param[in] thread: 一個指向線程標識符的指針,線程調(diào)用后,該值被設(shè)置為線程ID;pthread_t為unsigned long int
* @param[in] attr: 用來設(shè)置線程屬性
* @param[in] start_routine: 線程函數(shù)體,線程創(chuàng)建成功后,thread 指向的內(nèi)存單元從該地址開始運行
* @param[in] arg: 傳遞給線程函數(shù)體的參數(shù)
*
* @return 線程創(chuàng)建成功,則返回0,失敗則返回錯誤碼,并且 thread 內(nèi)容是未定義的
*/
int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*(*start_routine)(void*), void* arg);
例子test.c:創(chuàng)建一個線程,每1s打印一次。
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
void *thread_fun(void *arg)
{
s_thread_running = 1;
while (s_thread_running)
{
printf("thread run...\\n");
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, NULL); ///< 阻塞等待線程結(jié)束
if (ret != 0)
{
printf("pthread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread\\n");
exit(EXIT_SUCCESS);
}
`
編譯、運行:
`gcc test.c -o test -lpthread
`
2、pthread_join
`/**
* @brief 等待某個線程結(jié)束
*
* Detailed function description: 這是一個線程阻塞函數(shù),調(diào)用該函數(shù)則等到線程結(jié)束才繼續(xù)運行
*
* @param[in] thread: 某個線程的ID
* @param[in] retval: 用于獲取線程 start_routine 的返回值
*
* @return 線程創(chuàng)建成功,則返回0,失敗則返回錯誤碼,并且 thread 內(nèi)容是未定義的
*/
int pthread_join(pthread_t thread, void **retval);
`
例子test.c:創(chuàng)建一個線程,進行一次加法運算就返回。
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
void *thread_fun(void *arg)
{
static int res = 0;
int a = 1, b = 2;
res = a + b;
sleep(1);
printf("thread run, a + b = %d, addr = %p\\n", res, &res);
pthread_exit(&res);
}
int main(void)
{
int ret = 0;
int *retval = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("pthread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void **)&retval); ///< 阻塞等待線程結(jié)束
if (ret != 0)
{
printf("pthread_join error!\\n");
exit(EXIT_FAILURE);
}
if (retval != NULL)
{
printf("After Thread, retval = %d, addr = %p\\n", (int)*retval, retval);
}
exit(EXIT_SUCCESS);
}
`
編譯、運行:
3、pthread_exit
`/**
* @brief 退出線程
*
* Detailed function description
*
* @param[in] retval: 它指向的數(shù)據(jù)將作為線程退出時的返回值
*
* @return void
*/
void pthread_exit(void *retval);
`
- 線程將指定函數(shù)體中的代碼執(zhí)行完后自行結(jié)束;
- 線程執(zhí)行過程中,被同一進程中的其它線程(包括主線程)強制終止;
- 線程執(zhí)行過程中,遇到 pthread_exit() 函數(shù)結(jié)束執(zhí)行。
例子test.c:創(chuàng)建一個線程,每個1s打印一次,打印超過5次時調(diào)用pthread_exit退出。
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
static int cnt = 0;
s_thread_running = 1;
while (s_thread_running)
{
cnt++;
if (cnt > 5)
{
pthread_exit((void*)thread_exit_str);
}
printf("thread run...\\n");
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void**)&thread_res);
if (ret != 0)
{
printf("thread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread, thread_res = %s\\n", (char*)thread_res);
exit(EXIT_SUCCESS);
}
編譯、運行:
使用return退出線程與使用pthread_exit退出線程的區(qū)別?
return為通用的函數(shù)退出操作,pthread_exit專用與線程,既然pthread庫有提供專門的函數(shù),自然用pthread_exit會好些,雖然使用return也可以。
看看return退出線程與使用pthread_exit退出線程的具體區(qū)別:退出主線程。使用pthread_exit退出主線程只會終止當(dāng)前線程,不會影響進程中其它線程的執(zhí)行;使用return退出主線程,主線程退出執(zhí)行很快,所有線程都會退出。
例子:使用pthread_exit退出主線程
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
sleep(1);
printf("thread_fun run...\\n");
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
printf("main thread exit\\n");
pthread_exit(NULL);
}
`
編譯、運行:
例子:使用return退出主線程
`#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
sleep(1);
printf("thread_fun run...\\n");
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
printf("main thread exit\\n");
return 0;
}
`
編譯、運行:
4、pthread_self
`/**
* @brief 用來獲取當(dāng)前線程ID
*
* Detailed function description
*
* @param[in] void
*
* @return 返回線程id
*/
pthread_t pthread_self(void);
`
例子:
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < pthread.h >
static pthread_t s_thread_id;
static unsigned char s_thread_running = 0;
const static char *thread_exit_str = "thread_exit ok!";
void *thread_fun(void *arg)
{
static int cnt = 0;
s_thread_running = 1;
while (s_thread_running)
{
cnt++;
if (cnt > 5)
{
pthread_exit((void*)thread_exit_str);
}
printf("thread run(tid = %ld)...\\n", pthread_self());
sleep(1);
}
pthread_exit(NULL);
}
int main(void)
{
int ret = 0;
void *thread_res = NULL;
pid_t pid = getpid();
printf("pid = %d\\n", pid);
printf("Before Thread\\n");
ret = pthread_create(&s_thread_id, NULL, thread_fun, NULL);
if (ret != 0)
{
printf("thread_create error!\\n");
exit(EXIT_FAILURE);
}
ret = pthread_join(s_thread_id, (void**)&thread_res);
if (ret != 0)
{
printf("thread_join error!\\n");
exit(EXIT_FAILURE);
}
printf("After Thread, thread_res = %s\\n", (char*)thread_res);
exit(EXIT_SUCCESS);
}