質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Q&A

解決済

2回答

8650閲覧

マルチスレッドプログラム(Linux)によるシリアル通信 [ C言語 ]

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

0グッド

0クリップ

投稿2016/10/24 08:50

現在linuxマルチスレッドのプログラムでシリアル通信の受信をやっております.

プログラム起動後数回は受信に成功するのですが, その後全く受信することができません.原因がわかる方がいらっしゃいましたらご教授お願い致します.

C

1シリアルを開く関数 2int open_serial_port( char* modem_dev ){ 3 struct termios newtio; 4 5 fd[0] = open( modem_dev, O_RDWR | O_NOCTTY | O_NONBLOCK ); 6 if( fd[0] < 0 ){ 7 fprintf( stderr, "open error\n" ); 8 return -1; 9 } 10 11 fcntl( fd[p], F_SETOWN, getpid() ); 12 fcntl( fd[p], F_SETFL, FASYNC ); 13 tcgetattr( fd[p], &oldtio ); //save 14 15 newtio.c_iflag = 0; 16 newtio.c_oflag = 0; 17 newtio.c_cflag = 0; 18 newtio.c_lflag = 0; 19 newtio.c_line = 0; 20 bzero( newtio.c_cc, sizeof( newtio.c_cc ) ); 21 22 cfsetispeed( &newtio, BAUDRATE ); 23 cfsetospeed( &newtio, BAUDRATE ); 24 25 newtio.c_cflag |= ( CLOCAL | CREAD ); 26 27 newtio.c_cflag &= ~PARENB; 28 newtio.c_cflag &= ~CSTOPB; 29 newtio.c_cflag &= ~CSIZE; 30 newtio.c_cflag |= CS8; 31 newtio.c_cflag &= ~CRTSCTS; 32 33 newtio.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG ); 34 newtio.c_iflag = ( IGNPAR | IGNCR ); 35 newtio.c_iflag &= ( IXON | IXOFF | IXANY ); 36 37 newtio.c_oflag &= ~OPOST; 38 39 newtio.c_cc[VTIME] = 0; 40 newtio.c_cc[VMIN] = 1; 41 42 /* clear the modem line */ 43 tcflush( fd[p], TCIFLUSH ); 44 tcsetattr( fd[p], TCSANOW, &newtio ); 45 46 return 0; 47}

C

1シリアル受信のスレッドです 2 3void* thread0(){ 4 struct sigaction action; 5 struct sigevent evp; 6 7 k1 = 0; 8 k2 = 0; 9 10 pthread_mutex_init( &mutex0, NULL ); 11 pthread_cond_init( &cond0, NULL ); 12 13 memset( &action, 0, sizeof(action) ); 14 memset( &evp, 0, sizeof(evp) ); 15 16 action.sa_sigaction = SignalHandler; 17 action.sa_flags = SA_SIGINFO | SA_RESTART; 18 sigemptyset( &action.sa_mask ); 19 20 evp.sigev_notify = SIGEV_SIGNAL; 21 evp.sigev_signo = SIGIO; 22 23 if( sigaction( SIGIO, &action, NULL ) < 0 ){ 24 perror( "sigaction error" ); 25 return -1; 26 } 27 28 while(1){ 29 pthread_mutex_lock( &mutex0 ); 30 pthread_cond_wait( &cond0, &mutex0 ); 31 32 memset( buffer, '\0', sizeof(buffer) ); 33 34 k = read( fd[0], buffer, sizeof(buffer) ); 35 printf( "receive char : %d \n" , k ); 36 37 38 if( k > 0 ){ 39 40 // save buffer to rs_rbuffer and alz_buffer k byte ( k:受信したバイト数 ) 41 memcpy( &rs_rbuffer[k1], buffer, k ); 42 memcpy( &alz_buffer[k1], buffer, k ); 43 44 k1 += k; 45 k2 += k; 46 47 pthread_cond_signal( &cond1 ); 48 49 } 50 pthread_mutex_unlock( &mutex0 ); 51 52 } 53 54 pthread_exit(0); 55} 56

C

1シグナル 2 3// SIGIO handler 4void* SignalHandler(int signum, siginfo_t *info, void* ctxt){ 5 pthread_cond_signal( &cond0 ); 6} 7

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Pthreadプログラミング一般論の観点から、条件変数(pthread_cond_*)の利用方法が誤っています。特に待機関数pthread_cond_waitは、必ず 通常変数を用いた条件式とループ構造 としなければなりません。

条件変数とミューテックスを使ったスレッド間通知では、下記のようなコード構造をとる必要があります。(ここでは一方向通知を仮定)

C

1int condition; // 待機したい"条件"をあらわす通常の変数 2 // 複数の変数からなる複合条件の場合もある 3pthread_mutex_t mtx; 4pthread_cond_t cv; 5// (初期化処理は省略) 6 7// 通知側スレッド 8pthread_mutex_lock(&mtx); 9condition = 1;/* 待機条件を満たしたことを設定 */ 10pthread_cond_signal(&cv); 11pthread_mutex_unlock(&mtx); 12 13// 待機側スレッド 14pthread_mutex_lock(&mtx); 15while (!condition/*条件を満たしていない間 wait処理に入る*/) { 16 pthread_cond_wait(&cv, &mtx); 17} 18// 待機条件が満たされた状態で到達 19pthread_mutex_unlock(&mtx);

条件変数 Step-by-Step入門 の説明も参考に下さい。


通知スレッドの部分をシグナルハンドラで実装する場合も同様にして実装すればよいでしょうか?

いいえ。Linux(POSIX)シグナルハンドラ内部で行える処理は、通常コードに比べると大幅に制限されます。基本的に、ほとんど全てのCライブラリ関数は呼び出せないと考えてください。JP-CERTの シグナルハンドラ内では非同期安全な関数のみを呼び出す も参照ください。

厳格な話をすると、シグナルハンドラ本体では「volatile sig_atomic_t型の変数を書き換える」か「ごく一部の限られた関数(シグナルセーフ関数)を呼び出すこと」しか行ってはいけません。ミューテックスのロック操作や条件変数への通知操作はシグナルセーフではないため、何が起きても(期待通り動かなくても)文句を言えません。

シグナルハンドラと別スレッドの通信には、volatile sig_atomic_t型の変数を使うか、POSIXセマフォ(sem_post)しか通信の手段がありません。


非同期シグナルハンドラとPthreadマルチスレッド処理を組合せるのは、非常に高度なトピックですし、難解で間違えやすいプログラミングの代表格です。

非同期シグナルハンドラを使うのではなく、sigwait関数による同期的なシグナル待機に書き換えられるのであれば、後者の方がマルチスレッドプログラミングとの親和性が高くなります。詳細は シグナルハンドラを使わないでシグナルをハンドルするシグナルについて を参照ください。

投稿2016/10/25 03:04

編集2016/10/25 08:47
yohhoy

総合スコア6189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/10/25 07:37 編集

通知スレッドの部分をシグナルハンドラで実装する場合も同様にして実装すればよいでしょうか? 下記します. // SIGIO receive handler  通知側 void* SignalHandler(int signum, siginfo_t *info, void* ctxt){ pthread_mutex_lock( &mutex0 ); condition = 1; pthread_cond_signal( &cond0 ); pthread_mutex_unlock( &mutex0 ); } // 受信スレッド void* thread0(){ struct sigaction action; struct sigevent evp; k1 = 0; k2 = 0; pthread_mutex_init( &mutex0, NULL ); pthread_cond_init( &cond0, NULL ); memset( &action, 0, sizeof(action) ); memset( &evp, 0, sizeof(evp) ); action.sa_sigaction = SignalHandler; action.sa_flags = 0; action.sa_restorer = NULL; sigemptyset( &action.sa_mask ); evp.sigev_notify = SIGEV_SIGNAL; evp.sigev_signo = SIGIO; if( sigaction( SIGIO, &action, NULL ) < 0 ){ perror( "sigaction error" ); return -1; } while(1){ pthread_mutex_lock( &mutex0 ); while( !condition ){ pthread_cond_wait( &cond0, &mutex0 ); } condition = 0; memset( buffer, '\0', sizeof(buffer) ); k = 0; k = read( fd[0], buffer, sizeof(buffer) ); if( k > 0 ){ memcpy( &rs_rbuffer[k1], buffer, k ); k1 += k; k2 += k; pthread_cond_signal( &cond1 ); } } pthread_mutex_unlock( &mutex0 ); } pthread_exit(0); }
退会済みユーザー

退会済みユーザー

2016/10/25 12:06

非同期シグナルセーフな関数を確認してみましたが、本当に限定されており、プログラムの大幅な改善が必要なように思いました。 sigwait関数を利用したプログラムを再度コーディングして、 わからない場所はまた質問致します。 ありがとうございました。
guest

0

受信処理部分のデータがなかった場合に、pthread_cond_signalをコールしていないのは
気になります。

受信するデータが無かった場合は、pthread_cond_wait()解除する信号が送られないので
でデッドロックします。
ですので、下記の修正が必要かと思います。

受信処理の一部

C言語

1if( k > 0 ){ 2 ・・・省略・・・ 3# pthread_cond_signal( &cond1 ); 4} 5pthread_cond_signal( &cond1 ); # ここに移動 6pthread_mutex_unlock( &mutex0 );

投稿2016/10/24 11:16

編集2016/10/25 03:03
nagaetty

総合スコア1106

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/10/25 01:11

メインスレッドの他に, pthread_create によって2つのスレッドを作成しております. しかし現在は受信がうまく動作していないため、もう一つの処理部分のスレッドはコメントアウトしています.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問