最近在看 posix多線程程式設計 這是書上前面的一個鬧鐘的小程式,有幾個版本做了比較
1. 基本的同步版本
-
/*
-
* alarm.c
-
*
-
* Simple synchronous alarm program. This is used as a
-
* reference for progressive examples of asynchronous
-
* alarm programs.
-
*/
-
#include "errors.h"
-
-
int main (int argc, char **argv)
-
{
-
int seconds;
-
char line[128];
-
char message[64];
-
-
while (1)
-
{
-
printf("Alarm> ");
-
if (fgets(line, sizeof(line), stdin) == NULL)
-
exit(0);
-
if (strlen(line) <= 1)
-
continue;
-
-
/**
-
Parse input line into seconds (%d) and a message (%64[^\n]),
-
consisting of up to 64 characters separated from the seconds
-
by whitespace.
-
*/
-
if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2)
-
{
-
fprintf(stderr, "Bad command\n");
-
}
-
else
-
{
-
sleep(seconds);
-
printf("(%d) %s\n", seconds, message);
-
}
-
}
-
}
特點:同步實現非同步,鬧鐘請求後,程式睡眠等待鬧鐘時間到;
問題:用同步方式來實現非同步,一次只能處理一個鬧鐘請求;即程式睡眠時間到後才能進行下一次鬧鐘請求;
運行結果。
-
# ./alarm
-
Alarm> 5
-
Bad command
-
Alarm> 5 this is a test with 5 seconds
-
(5) this is a test with 5 seconds //等待5秒並列印該訊息
-
Alarm> 10 the seconds with 10 seconds
-
(10) the seconds with 10 seconds //等待10秒並列印該訊息
-
Alarm>
2. 多進程版本
-
/*
-
* alarm_fork.c
-
*
-
* This version of alarm.c uses fork to create a new process to
-
* wait for each alarm to expire.
-
*/
-
#include <sys/types.h>
-
#include <wait.h>
-
#include "errors.h"
-
-
int main(int argc, char **argv)
-
{
-
int status;
-
char line[128];
-
int seconds;
-
pid_t pid;
-
char message[64];
-
-
while (1)
-
{
-
printf ("Alarm> ");
-
if (fgets(line, sizeof(line), stdin) == NULL) exit(0);
-
if (strlen(line) <= 1) continue;
-
-
/**
-
Parse input line into seconds (%d) and a message (%64[^\n]),
-
consisting of up to 64 characters separated from the seconds
-
by whitespace.
-
*/
-
if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2)
-
{
-
fprintf(stderr, "Bad command\n");
-
}
-
else
-
{
-
pid = fork();
-
if (pid == (pid_t)-1)
-
errno_abort("Fork");
-
if (pid == (pid_t)0)
-
{
-
/*
-
* If we're in the child, wait and then print a message
-
*/
-
sleep(seconds);
-
printf("pid = %d, (%d) %s\n", pid, seconds, message);
-
exit(0);
-
}
-
else
-
{
-
/*
-
* In the parent, call waitpid() to collect any children that
-
* have already terminated.
-
*/
-
do
-
{
-
pid = waitpid((pid_t)-1, NULL, WNOHANG);
-
if (pid == (pid_t)-1)
-
errno_abort("Wait for child");
-
} while (pid != (pid_t)0);
-
}
-
}
-
}
特點:在子進程中非同步地調用sleep函數,而父進程繼續運行;
問題:對每次鬧鐘請求,使用fork建立子進程,程式開銷過大;
waitpid()函數
運行結果。
-
Alarm> 3 test 1 //輸入命令
-
Alarm> 5 test 2 //輸入命令
-
Alarm> (3) test 1 //等待3秒並列印該訊息
-
10 test 3 //輸入命令
-
Alarm> (5) test 2 //等待5秒並列印該訊息
-
-
Alarm> (10) test 3 //等待10秒並列印該訊息
-
-
Alarm>
3.多線程版本
-
/*
-
* alarm_fork.c
-
*
-
* This version of alarm.c uses pthread_create to create a
-
* separate thread to wait for each alarm to expire.
-
*/
-
#include <pthread.h>
-
#include "errors.h"
-
-
typedef struct alarm_tag {
-
int seconds;
-
char message[64];
-
} alarm_t;
-
-
void *alarm_thread (void *arg)
-
{
-
alarm_t *alarm = (alarm_t*)arg;
-
int status;
-
-
status = pthread_detach (pthread_self ());
-
if (status != 0)
-
err_abort (status, "Detach thread");
-
sleep (alarm->seconds);
-
printf ("(%d) %s\n", alarm->seconds, alarm->message);
-
free (alarm);
-
return NULL;
-
}
-
-
int main (int argc, char *argv[])
-
{
-
int status;
-
char line[128];
-
alarm_t *alarm;
-
pthread_t thread;
-
-
while (1) {
-
printf ("Alarm> ");
-
if (fgets (line, sizeof (line), stdin) == NULL) exit (0);
-
if (strlen (line) <= 1) continue;
-
alarm = (alarm_t*)malloc (sizeof (alarm_t));
-
if (alarm == NULL)
-
errno_abort ("Allocate alarm");
-
-
/*
-
* Parse input line into seconds (%d) and a message
-
* (%64[^\n]), consisting of up to 64 characters
-
* separated from the seconds by whitespace.
-
*/
-
if (sscanf (line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) {
-
fprintf (stderr, "Bad command\n");
-
free (alarm);
-
} else {
-
status = pthread_create(&thread, NULL, alarm_thread, alarm);
-
if (status != 0)
-
err_abort (status, "Create alarm thread");
-
}
-
}
-
}
特點:在該例子中,alarm線程調用pthread_detach()函數來分離自己,通知pthreads不必關心它的終止時間和退出狀態;因此不需要等待線程結束,除非希望獲得它的傳回值。alarm線程的資源在它終止後立即回收。
一般地,pthreads會儲存線程的資源以使其他線程瞭解它已經終止並獲得其最終結果。在本例中,alarm線程負責自己分離自己。
該版本用到以下函數:
運行結果。
-
# ./alarm_thread
-
Alarm> 5 atest
-
Alarm> 10 btest
-
Alarm> (5) atest
-
-
Alarm> 15 ctest
-
Alarm> (10) btest
-
Alarm> (15) ctest
-
-
Alarm>
4. 小結
多進程版本
多線程版本
-
線程間傳遞訊息更快
-
不需要映射共用記憶體;
-
不需要通過管道讀寫;
-
不需要擔心進程間傳送的地址指標是否一致;
多線程編程優點
多線程編程缺點
何種應用適合使用多線程?
-
計算密集型應用,為了能在多處理器系統上運行,將這些計算分解到多個線程中實現;
-
IO密集型應用,為提高效能,將IO操作重疊;如分布式伺服器;
我在ubuntu 10.10進行調試,用GCC編譯時間出現如下的報錯資訊。
1.
fatal error: errors.h: No such file or directory
然後我將errors.h換成error.h,這行代碼就沒有報錯,但是接下來就出現了這個問題
undefined reference to `error_abort'
undefined reference to `errno_abort'
undefined reference to `err_abort'
這個問題一直沒得到解決,不知道是這本書太舊而現在linux版本太高不相容的原因還是怎麼的,在網上查也一直沒查到原因,最後只能將其中的錯誤處理機制全部屏蔽掉, 如果哪位大牛知道解決方案的話,請不吝賜教。
2.
undefined reference to `pthread_detach'
undefined reference to `pthread_create'
這是由於pthread 庫不是 Linux 系統預設的庫,串連時需要使用靜態庫 libpthread.a,所以在使用pthread_create()建立線程時,需要連結該庫。
問題解決:
在編譯中要加 -lpthread參數
gcc alarm_thread.c -o alarm_thread -lpthread