『壹』 關於linux signal的問題
也就是說,當GPS數據准備好後會發送signal給你們自己寫的平台軟體,相當於請求刷屏幕,然後平台軟體執行刷屏幕操作,這兩個之間需要一個同步關系就是說,當有請求後我才去刷屏幕操作。
這種情況不是因為平台進程接受不到signal,而是收到了signal信號而且正確執行了sem_post操作(你可以在signal handler中加入列印調試語句看看),因為你的刷屏幕操作線程執行時間太長了,導致連續執行好幾次屏幕操作,這是種惡性循環(因為gps軟體每次數據准備好就發送個signal,而你的 signal在每次捕捉到signal後就執行一次sem_post,然而你的刷屏幕操作時間太長了當執行完一次刷屏幕操作後再次調用sem_wait的時候已經有多個信號量資源了也就是消費跟不上生產,信號量post次數比wait次數多)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
sem_t lock;
int gps_data = 0;
/* fflush screen thread */
void *gps_data_process (void *arg)
{
while (1)
{
/* wait gps data is ready */
/* second run sem_wait will by more semaphore it will not block */
sem_wait(&lock);
/* ok data is ready */
printf("Data is [%d]\n", gps_data);
/* simulate a long procees time */
sleep(100);
}
}
/* SIGUSR1 handler */
void gps_data_request(int sig)
{
if (sig == SIGUSR1)
{
/* ok gps data is ready so request process */
sem_post(&lock);
}
}
int main(int argc, char **argv)
{
pthread_t tid;
struct sigaction action;
/* initialize semaphore */
if (sem_init(&lock, 0, 0) == -1)
{
perror("sem_init");
exit(1);
}
action.sa_handler = gps_data_request;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
/* caught signal SIGUSR1 */
if (sigaction(SIGUSR1, &action, NULL))
{
perror("sigaction");
exit(1);
}
/* create a thread */
if (pthread_create(&tid, NULL, gps_data_process, NULL) == -1)
{
perror("pthread_create");
exit(1);
}
while (1)
{
printf("[GPS]>>>");
/* gps get data ready */
scanf("%d", &gps_data);
if (gps_data)
{
/* simulate gps program send signal to platform process */
raise(SIGUSR1);
}
sleep(1);
}
return 0;
}
『貳』 Linux環境下使用signal函數進行進程間通信的問題
測試了一下,三個進程都會收到SIGINT信號。
原程序中,child1, child2都收到SIGINT信號,調用stop(), 之後被喚醒,列印"child process ... is killed by parent!",事實上kill這兩個child的不是parent,是它們自己的SIGINT。
放到①處,child1收到SIGINT信號,默認的行為是把自己殺了,當然也來不及列印任何東西了。child2收到SIGINT信號,打斷waiting(),列印"child process 2 ...",然後退出。殺死它的也不是SIGUSR2信號。
放到②處,child1, child2收到SIGINT信號,默認的行為是立即把自己殺了,也來不及列印任何東西了。
測試方法:
// 列印誰執行、被什麼信號打斷
static void stop(int signal) {
printf("stop %d by signal %d\n", getpid(), signal);
wait_mark=0;
}
// 在parent進程中,列印各進程id
printf("parent %d, child1 %d, child2 %d\n",getpid(),p1,p2);
如果讓parent成為殺死child的兇手,可以在child1,child2中加入:
signal(SIGINT, keep_me_alive);
// 不理睬SIGINT信號
static void keep_me_alive(int signal) {
}
這時列印結果就一樣了
『叄』 Linux信號量
信號量是包含一個非負整數型的變數,並且帶有兩個原子操作wait和signal。Wait還可以被稱為down、P或lock,signal還可以被稱為up、V、unlock或post。在UNIX的API中(POSIX標准)用的是wait和post。
對於wait操作,如果信號量的非負整形變數S大於0,wait就將其減1,如果S等於0,wait就將調用線程阻塞;對於post操作,如果有線程在信號量上阻塞(此時S等於0),post就會解除對某個等待線程的阻塞,使其從wait中返回,如果沒有線程阻塞在信號量上,post就將S加1.
由此可見,S可以被理解為一種資源的數量,信號量即是通過控制這種資源的分配來實現互斥和同步的。如果把S設為1,那麼信號量即可使多線程並發運行。另外,信號量不僅允許使用者申請和釋放資源,而且還允許使用者創造資源,這就賦予了信號量實現同步的功能。可見信號量的功能要比互斥量豐富許多。
POSIX信號量是一個sem_t類型的變數,但POSIX有兩種信號量的實現機制: 無名信號量 和 命名信號量 。無名信號量只可以在共享內存的情況下,比如實現進程中各個線程之間的互斥和同步,因此無名信號量也被稱作基於內存的信號量;命名信號量通常用於不共享內存的情況下,比如進程間通信。
同時,在創建信號量時,根據信號量取值的不同,POSIX信號量還可以分為:
下面是POSIX信號量函數介面:
信號量的函數都以sem_開頭,線程中使用的基本信號函數有4個,他們都聲明在頭文件semaphore.h中,該頭文件定義了用於信號量操作的sem_t類型:
【sem_init函數】:
該函數用於創建信號量,原型如下:
該函數初始化由sem指向的信號對象,設置它的共享選項,並給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示信號量是當前進程的局部信號量,否則信號量就可以在多個進程間共享,value為sem的初始值。
該函數調用成功返回0,失敗返回-1。
【sem_destroy函數】:
該函數用於對用完的信號量進行清理,其原型如下:
成功返回0,失敗返回-1。
【sem_wait函數】:
該函數用於以原子操作的方式將信號量的值減1。原子操作就是,如果兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。其原型如下:
sem指向的對象是sem_init調用初始化的信號量。調用成功返回0,失敗返回-1。
sem_trywait()則是sem_wait()的非阻塞版本,當條件不滿足時(信號量為0時),該函數直接返回EAGAIN錯誤而不會阻塞等待。
sem_timedwait()功能與sem_wait()類似,只是在指定的abs_timeout時間內等待,超過時間則直接返回ETIMEDOUT錯誤。
【sem_post函數】:
該函數用於以原子操作的方式將信號量的值加1,其原型如下:
與sem_wait一樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1。
【sem_getvalue函數】:
該函數返回當前信號量的值,通過restrict輸出參數返回。如果當前信號量已經上鎖(即同步對象不可用),那麼返回值為0,或為負數,其絕對值就是等待該信號量解鎖的線程數。
【實例1】:
【實例2】:
之所以稱為命名信號量,是因為它有一個名字、一個用戶ID、一個組ID和許可權。這些是提供給不共享內存的那些進程使用命名信號量的介面。命名信號量的名字是一個遵守路徑名構造規則的字元串。
【sem_open函數】:
該函數用於創建或打開一個命名信號量,其原型如下:
參數name是一個標識信號量的字元串。參數oflag用來確定是創建信號量還是連接已有的信號量。
oflag的參數可以為0,O_CREAT或O_EXCL:如果為0,表示打開一個已存在的信號量;如果為O_CREAT,表示如果信號量不存在就創建一個信號量,如果存在則打開被返回,此時mode和value都需要指定;如果為O_CREAT|O_EXCL,表示如果信號量存在則返回錯誤。
mode參數用於創建信號量時指定信號量的許可權位,和open函數一樣,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。
value表示創建信號量時,信號量的初始值。
【sem_close函數】:
該函數用於關閉命名信號量:
單個程序可以用sem_close函數關閉命名信號量,但是這樣做並不能將信號量從系統中刪除,因為命名信號量在單個程序執行之外是具有持久性的。當進程調用_exit、exit、exec或從main返回時,進程打開的命名信號量同樣會被關閉。
【sem_unlink函數】:
sem_unlink函數用於在所有進程關閉了命名信號量之後,將信號量從系統中刪除:
【信號量操作函數】:
與無名信號量一樣,操作信號量的函數如下:
命名信號量是隨內核持續的。當命名信號量創建後,即使當前沒有進程打開某個信號量,它的值依然保持,直到內核重新自舉或調用sem_unlink()刪除該信號量。
無名信號量的持續性要根據信號量在內存中的位置確定:
很多時候信號量、互斥量和條件變數都可以在某種應用中使用,那這三者的差異有哪些呢?下面列出了這三者之間的差異:
『肆』 fork(),signal(),kill(),wait()這幾個命令是c函數還是linux操作系統的系統調用
你可以這么理解:
這幾個都是linux系統編程中的函數,C語言寫的;當然他也是系統調用介面;他們並不沖突;你自己寫個程序調用這些介面也是可以的; APUE中有介紹這幾個函數;