Я создал тему, которая может читать сообщения Bluetooth, отправленные с телефона. Моя проблема возникла, когда я понял, что не могу безопасно убить эту нить. До сих пор методом был пользовательский ввод, который вызывал exit()
из этого потока, все странные вещи начали происходить, когда я переместил это из этого потока в основной (обнаружен разрыв стека и ошибка сегментации). Очевидно, что этот подход также не очень хорошо масштабировался бы, если бы у меня был другой поток для вызовов Wi-Fi или я просто не хотел выходить из системы вообще.
Пока это мой код.
Структура для Связанные с Bluetooth вещи для передачи в поток:
typedef struct {
struct sockaddr_rc loc_addr;
struct sockaddr_rc rem_addr;
socklen_t opt;
char blu_buffer[1024];
int blu_sock;
} Bluetooth_stuff;
Поток прослушивания новых соединений:
void * BluetoothListiner(void * argv){
Bluetooth_stuff * bt_set = (Bluetooth_stuff * ) argv;
int bytes_read;
int local_client;
int option = 0;
listen(bt_set->blu_sock, 1);
memset(bt_set->blu_buffer, 0, sizeof(bt_set->blu_buffer));
while(true){
local_client = accept(bt_set->blu_sock, (struct sockaddr *)&((*bt_set).rem_addr), &((*bt_set).opt));
// read data from the client
bytes_read = read(local_client, bt_set->blu_buffer, sizeof(bt_set->blu_buffer));
if( bytes_read > 0 ) {
// process data
}
}
else{
// accept again?
}
// clear the buffer
memset(bt_set->blu_buffer, 0, sizeof(bt_set->blu_buffer));
// close connection
close(local_client);
usleep(10);
}
}
Конфигурация сокета:
void BluetoothSocketConfig(Bluetooth_stuff * bt_set){
// allocate socket
bt_set->blu_sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
bt_set->opt= sizeof(bt_set->rem_addr);
(*bt_set).loc_addr.rc_family = AF_BLUETOOTH;
(*bt_set).loc_addr.rc_bdaddr = *BDADDR_ANY;
(*bt_set).loc_addr.rc_channel = (uint8_t) 1;
// bind socket to port 1 of the first available
bind(bt_set->blu_sock, (struct sockaddr *)&(bt_set->loc_addr), sizeof(bt_set->loc_addr));
}
Тестирование основного:
int main(int argc, char *argv[]){
Bluetooth_stuff bt_set;
BluetoothSocketConfig(&bt_set);
pthread_create(&blu_listiner, NULL, BluetoothListiner, bt_set);
while(1); // I modify that for testing to exit, having a global flag also gave me segmentation errors somehow
}
Вызов exit(1)
не очищает другие потоки, а pthread_kill
или pthread_cancel
из другого потока часто приводят к тому, что процессы, все еще работающие в фоновом режиме, не позволяют мне снова запустить приложение, не убивая процессы вручную с помощью ps -A
и kill -9 PROCESS
.
Исходя из этой статьи Я решил, что лучший способ сделать это - ввести в поток оператор if
и поместить его pthread_exit
в забвение. Например:
if(external_exit){
ret2 = 200;
pthread_exit(&ret2);
}
Теперь, когда read()
является блокирующим вызовом, я никогда не смогу прийти к выражению if
без каких-либо внешних событий. Этот ответ предлагает использовать тайм-аут для достижения этого, и я следовал синтаксису этого ответа , чтобы выйти из read()
через определенный период. Таким образом, я добавил это перед основным временем l oop потока (я думаю, что это должно быть определено только один раз, а не для каждого l oop, хотя и не уверен, поскольку не смог найти конкретный пример c).
Теперь моя проблема заключалась в том, что он заблокировал бы read()
на первом l oop, но затем пропустил бы его, как будто ничего, и просто l oop на неопределенный срок. Я попытался «включить» read()
, повторно вызвав accept()
listen()
и bind()
безуспешно. Кажется, использование select()
является предпочтительным вариантом для первой проверки, если есть что читать, но как указано в руководстве
" В Linux select () может сообщить дескриптор файла сокета как "готовый к чтению", хотя, тем не менее, последующие блоки чтения читаются. Это может, например, произойти, когда данные поступили, но при проверке имеет неправильную контрольную сумму и отбрасывается"
Так что даже при ее использовании (который я я не уверен, что будет работать с Bluetooth-сокетами, как это было бы с TCP-соединениями) всегда есть вероятность, что он все равно застрянет на read()
без возможности убить его безопасно.
1) Как я могу безопасно уничтожить этот поток (или любой блокирующий поток)?
2) Действительно ли select()
действительно необходим для подхода с блокировкой, поскольку у меня нет нескольких соединений?
3) Как выполнить процедуру для правильного использования read()
в режим блокировки после начального тайм-аута?
4) Кроме различной инициализации все сокеты в основном эквивалентны unix / can / tcp / bluetooth?
5) Любые другие способы получить Что я хочу или серьезно fl aws в логи c с моей стороны?
Спасибо за любую помощь, если у кого-то есть ссылка на реализацию потока на сервере Bluetooth, я был бы рад видеть это (или любой другой сокет unix / can / tcp).